Merge "SurfaceFlinger: expose vsync id extra buffers" into sc-dev
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/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/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 2362c9e..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
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index 819a6a4..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
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/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/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/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 e3aaf6d..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();
@@ -1442,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;
@@ -1469,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;
         }
@@ -1856,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;
@@ -1913,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;
@@ -1924,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;
             }
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/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 550803d..4493a21 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>
@@ -1802,52 +1802,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 e56670d..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.
      *
@@ -545,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,
@@ -572,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,
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e7abfe6..bd9f066 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,
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 bbf0906..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; }
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 6b085a3..dc2dd29 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -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/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/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_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/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 825626a..8d1258a 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -173,7 +173,7 @@
         "SurfaceFlingerDefaultFactory.cpp",
         "SurfaceInterceptor.cpp",
         "SurfaceTracing.cpp",
-        "TransactionCompletedThread.cpp",
+        "TransactionCallbackInvoker.cpp",
     ],
 }
 
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/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/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/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 31d1245..1f0f3c3 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayMode.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -86,8 +86,8 @@
             return *this;
         }
 
-        Builder& setConfigGroup(int32_t configGroup) {
-            mDisplayMode->mConfigGroup = configGroup;
+        Builder& setGroup(int32_t group) {
+            mDisplayMode->mGroup = group;
             return *this;
         }
 
@@ -119,7 +119,10 @@
     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) {}
@@ -132,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/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..df14003 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -841,13 +841,35 @@
         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();
 
+    if (stateToCommit != nullptr) {
+        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) {
@@ -1474,11 +1494,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 3930a81..36ae19c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -54,7 +54,7 @@
 #include "Scheduler/Seamlessness.h"
 #include "SurfaceFlinger.h"
 #include "SurfaceTracing.h"
-#include "TransactionCompletedThread.h"
+#include "TransactionCallbackInvoker.h"
 
 using namespace android::surfaceflinger;
 
@@ -309,6 +309,20 @@
 
         // 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;
     };
 
     /*
@@ -447,7 +461,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 +626,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 +887,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.
@@ -971,6 +1004,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(
@@ -979,7 +1013,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>&) {}
@@ -1115,6 +1149,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 d57d0da..04e9a6d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -67,9 +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>
@@ -887,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;
     }
 
@@ -900,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 ||
@@ -918,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
@@ -949,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;
@@ -966,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());
@@ -983,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();
@@ -1024,7 +1023,7 @@
         modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated);
 
         updatePhaseConfiguration(refreshRate.getFps());
-        mScheduler->setConfigChangePending(true);
+        mScheduler->setModeChangePending(true);
     }
 
     if (mRefreshRateOverlay) {
@@ -1032,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) {
@@ -1042,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;
         }
 
@@ -1067,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();
@@ -1081,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);
 
@@ -1105,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;
@@ -1178,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.
@@ -1188,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,
@@ -1627,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;
@@ -1640,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,
@@ -1829,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) {
@@ -1920,7 +1919,7 @@
         mScheduler->chooseRefreshRateForContent();
     }
 
-    ON_MAIN_THREAD(performSetActiveConfig());
+    ON_MAIN_THREAD(performSetActiveMode());
 
     updateCursorAsync();
     updateInputFlinger();
@@ -2195,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()) {
@@ -2370,7 +2369,7 @@
                                 .setVsyncPeriod(hwcMode.vsyncPeriod)
                                 .setDpiX(hwcMode.dpiX)
                                 .setDpiY(hwcMode.dpiY)
-                                .setConfigGroup(hwcMode.configGroup)
+                                .setGroup(hwcMode.configGroup)
                                 .build());
     }
     return modes;
@@ -2391,7 +2390,7 @@
         if (event.connection == hal::Connection::CONNECTED) {
             auto supportedModes = loadSupportedDisplayModes(displayId);
             const auto activeModeHwcId = getHwComposer().getActiveMode(displayId);
-            LOG_ALWAYS_FATAL_IF(!activeModeHwcId, "HWC returned no active config");
+            LOG_ALWAYS_FATAL_IF(!activeModeHwcId, "HWC returned no active mode");
 
             const auto activeMode = *std::find_if(supportedModes.begin(), supportedModes.end(),
                                                   [activeModeHwcId](const DisplayModePtr& mode) {
@@ -2675,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) {
@@ -2935,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
@@ -2996,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(
@@ -3555,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;
@@ -3575,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;
 
@@ -3695,7 +3692,7 @@
     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);
     }
 
@@ -3708,7 +3705,7 @@
     }
     if (layer == nullptr) {
         for (auto& [listener, callbackIds] : s.listeners) {
-            mTransactionCompletedThread.registerUnpresentedCallbackHandle(
+            mTransactionCallbackInvoker.registerUnpresentedCallbackHandle(
                     new CallbackHandle(listener, callbackIds, s.surface));
         }
         return 0;
@@ -3939,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)) {
@@ -4001,9 +3999,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;
@@ -4540,8 +4540,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);
@@ -4960,8 +4960,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:
@@ -5003,13 +5003,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:
@@ -5384,7 +5384,7 @@
             }
             case 1035: {
                 const int modeId = data.readInt32();
-                mDebugDisplayConfigSetByBackdoor = false;
+                mDebugDisplayModeSetByBackdoor = false;
 
                 const auto displayId = getInternalDisplayId();
                 if (!displayId) {
@@ -5392,12 +5392,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;
             }
@@ -5476,14 +5476,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);
@@ -6070,7 +6069,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);
@@ -6080,10 +6079,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;
@@ -6091,23 +6090,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;
     }
 
@@ -6122,42 +6120,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) {
@@ -6167,34 +6166,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;
     }
@@ -6208,7 +6207,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();
@@ -6219,7 +6218,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();
@@ -6349,16 +6348,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) {
@@ -6398,7 +6396,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");
         }
     }));
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 49308a4..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
@@ -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;
@@ -651,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.
@@ -679,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);
@@ -931,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.
@@ -1049,9 +1048,9 @@
      * 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;
     }
 
@@ -1166,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;
@@ -1251,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;
@@ -1286,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/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 efa15f1..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>
@@ -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);
     }
@@ -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",
-                         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;
                 }
             }
@@ -348,11 +347,11 @@
             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"),
@@ -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));
         }
     }
 
@@ -409,14 +408,14 @@
         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));
+                          SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate));
                 waitForDisplayTransaction(EXTERNAL_DISPLAY);
-                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                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(),
@@ -516,14 +515,14 @@
         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));
+                          SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate));
                 waitForDisplayTransaction(EXTERNAL_DISPLAY);
-                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                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(),
@@ -632,14 +631,14 @@
         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 (size_t 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));
+                          SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
+                                                                            modes[i].refreshRate,
+                                                                            modes[i].refreshRate,
+                                                                            modes[i].refreshRate,
+                                                                            modes[i].refreshRate));
                 waitForDisplayTransaction(EXTERNAL_DISPLAY);
-                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                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));
+                          SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate));
                 waitForDisplayTransaction(EXTERNAL_DISPLAY);
-                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                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));
+                          SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate));
                 waitForDisplayTransaction(EXTERNAL_DISPLAY);
-                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                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(),
@@ -822,8 +820,8 @@
             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);
         }
 
@@ -848,11 +846,11 @@
             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);
         }
     }
 
@@ -881,14 +879,14 @@
 
         // Verify that the active mode and the supported moded are updated
         {
-            DisplayConfig config;
-            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-            EXPECT_EQ(ui::Size(800, 1600), config.resolution);
-            EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+            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<DisplayConfig> configs;
-            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
-            EXPECT_EQ(configs.size(), 1);
+            Vector<ui::DisplayMode> modes;
+            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
+            EXPECT_EQ(modes.size(), 1);
         }
 
         // Send another hotplug connected event
@@ -919,27 +917,27 @@
 
         // Verify that the active mode and the supported moded are updated
         {
-            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);
         }
 
-        Vector<DisplayConfig> configs;
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
-        EXPECT_EQ(configs.size(), 3);
+        Vector<ui::DisplayMode> modes;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
+        EXPECT_EQ(modes.size(), 3);
 
-        EXPECT_EQ(ui::Size(800, 1600), configs[0].resolution);
-        EXPECT_EQ(1e9f / 16'666'666, configs[0].refreshRate);
+        EXPECT_EQ(ui::Size(800, 1600), modes[0].resolution);
+        EXPECT_EQ(1e9f / 16'666'666, modes[0].refreshRate);
 
-        EXPECT_EQ(ui::Size(800, 1600), configs[1].resolution);
-        EXPECT_EQ(1e9f / 11'111'111, configs[1].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), configs[2].resolution);
-        EXPECT_EQ(1e9f / 8'333'333, configs[2].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 = configs.size() - 1; i >= 0; i--) {
+        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) {
@@ -952,22 +950,22 @@
             }
 
             EXPECT_EQ(NO_ERROR,
-                      SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
-                                                                          configs[i].refreshRate,
-                                                                          configs[i].refreshRate,
-                                                                          configs[i].refreshRate,
-                                                                          configs[i].refreshRate));
+                      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(waitForConfigChangedEvent(hwcDisplayId, i))
+            EXPECT_TRUE(waitForModeChangedEvent(hwcDisplayId, i))
                     << "Failure while switching to mode " << i;
 
-            DisplayConfig config;
-            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-            EXPECT_EQ(ui::Size(800, 1600), config.resolution);
-            EXPECT_EQ(configs[i].refreshRate, config.refreshRate);
+            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);
         }
     }
 
@@ -1168,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 9b29b70..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",
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/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/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 510b620..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;
@@ -168,25 +168,25 @@
     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) {
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 6b145b0..ce2bfef 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -210,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);
@@ -648,7 +648,7 @@
                             .setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)
                             .setDpiX(FakeHwcDisplayInjector::DEFAULT_DPI)
                             .setDpiY(FakeHwcDisplayInjector::DEFAULT_DPI)
-                            .setConfigGroup(0)
+                            .setGroup(0)
                             .build();
 
             DisplayModes modes{activeMode};
@@ -761,7 +761,7 @@
 
 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/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/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;
 }