Merge "SurfaceFlinger: Add ClientCache dumps" into sc-dev
diff --git a/Android.bp b/Android.bp
index 9829c7f..298c01a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,41 @@
+package {
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change filtered out the below license kinds as false-positives:
+//   SPDX-license-identifier-LGPL
+//   SPDX-license-identifier-LGPL-2.1
+//   SPDX-license-identifier-LGPL-3.0
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-BSD",
+        "SPDX-license-identifier-MIT",
+        "SPDX-license-identifier-Unicode-DFS",
+        "legacy_notice",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 ndk_headers {
     name: "libandroid_headers",
     from: "include/android",
@@ -43,3 +81,8 @@
         ":framework_native_aidl_gui",
     ],
 }
+
+cc_library_headers{
+    name: "libandroid_headers_private",
+    export_include_dirs: ["include/private"],
+}
\ No newline at end of file
diff --git a/aidl/gui/android/hardware/display/IDeviceProductInfoConstants.aidl b/aidl/gui/android/hardware/display/IDeviceProductInfoConstants.aidl
new file mode 100644
index 0000000..7cc272a
--- /dev/null
+++ b/aidl/gui/android/hardware/display/IDeviceProductInfoConstants.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.hardware.display;
+
+/** @hide */
+interface IDeviceProductInfoConstants {
+    /** The device connection to the display sink is unknown. */
+    const int CONNECTION_TO_SINK_UNKNOWN = 0;
+
+    /** The device is built-in in the display sink. */
+    const int CONNECTION_TO_SINK_BUILT_IN = 1;
+
+    /** The device is directly connected to the display sink. */
+    const int CONNECTION_TO_SINK_DIRECT = 2;
+
+    /** The device is transitively connected to the display sink. */
+    const int CONNECTION_TO_SINK_TRANSITIVE = 3;
+}
\ No newline at end of file
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index e7d0ad0..aa0ef25 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -1,5 +1,22 @@
 // Copyright 2012 The Android Open Source Project
 
+package {
+    default_applicable_licenses: ["frameworks_native_cmds_atrace_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_cmds_atrace_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_binary {
     name: "atrace",
     srcs: ["atrace.cpp"],
diff --git a/cmds/bugreport/Android.bp b/cmds/bugreport/Android.bp
index 24044a6..8262aed 100644
--- a/cmds/bugreport/Android.bp
+++ b/cmds/bugreport/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "bugreport",
     srcs: ["bugreport.cpp"],
diff --git a/cmds/bugreport/OWNERS b/cmds/bugreport/OWNERS
index 1ba7cff..2a9b681 100644
--- a/cmds/bugreport/OWNERS
+++ b/cmds/bugreport/OWNERS
@@ -1,6 +1,4 @@
 set noparent
 
-felipeal@google.com
 nandana@google.com
 jsharkey@android.com
-enh@google.com
diff --git a/cmds/bugreportz/Android.bp b/cmds/bugreportz/Android.bp
index 924a3a3..332f858 100644
--- a/cmds/bugreportz/Android.bp
+++ b/cmds/bugreportz/Android.bp
@@ -1,5 +1,14 @@
 // bugreportz
 // ==========
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "bugreportz",
 
diff --git a/cmds/bugreportz/OWNERS b/cmds/bugreportz/OWNERS
index 1ba7cff..2a9b681 100644
--- a/cmds/bugreportz/OWNERS
+++ b/cmds/bugreportz/OWNERS
@@ -1,6 +1,4 @@
 set noparent
 
-felipeal@google.com
 nandana@google.com
 jsharkey@android.com
-enh@google.com
diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp
index 8ea71cd..c900a24 100644
--- a/cmds/cmd/Android.bp
+++ b/cmds/cmd/Android.bp
@@ -1,3 +1,20 @@
+package {
+    default_applicable_licenses: ["frameworks_native_cmds_cmd_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_cmds_cmd_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_library_static {
     name: "libcmd",
 
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 34e9a85..f48f1fb 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -13,6 +13,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "dumpstate_cflag_defaults",
     cflags: [
diff --git a/cmds/dumpstate/OWNERS b/cmds/dumpstate/OWNERS
index 1ba7cff..2a9b681 100644
--- a/cmds/dumpstate/OWNERS
+++ b/cmds/dumpstate/OWNERS
@@ -1,6 +1,4 @@
 set noparent
 
-felipeal@google.com
 nandana@google.com
 jsharkey@android.com
-enh@google.com
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index f99588f..91aa018 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -1,3 +1,20 @@
+package {
+    default_applicable_licenses: ["frameworks_native_cmds_dumpsys_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_cmds_dumpsys_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_defaults {
     name: "dumpsys_defaults",
 
diff --git a/cmds/dumpsys/OWNERS b/cmds/dumpsys/OWNERS
index 1ba7cff..2a9b681 100644
--- a/cmds/dumpsys/OWNERS
+++ b/cmds/dumpsys/OWNERS
@@ -1,6 +1,4 @@
 set noparent
 
-felipeal@google.com
 nandana@google.com
 jsharkey@android.com
-enh@google.com
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index e182b9d..6854c75 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -1,4 +1,13 @@
 // Build the unit tests for dumpsys
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_cmds_dumpsys_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_cmds_dumpsys_license"],
+}
+
 cc_test {
     name: "dumpsys_test",
     test_suites: ["device-tests"],
diff --git a/cmds/flatland/Android.mk b/cmds/flatland/Android.mk
index 7aa111c..754a99c 100644
--- a/cmds/flatland/Android.mk
+++ b/cmds/flatland/Android.mk
@@ -11,6 +11,9 @@
 LOCAL_CFLAGS := -Wall -Werror
 
 LOCAL_MODULE:= flatland
+LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS:= notice
+LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE
 
 LOCAL_MODULE_TAGS := tests
 
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 3a3df08..01f7d30 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -19,7 +19,7 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <gui/SurfaceComposerClient.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 
 namespace android {
 
@@ -227,15 +227,15 @@
         return false;
     }
 
-    DisplayConfig config;
-    status_t err = mSurfaceComposerClient->getActiveDisplayConfig(dpy, &config);
+    ui::DisplayMode mode;
+    status_t err = mSurfaceComposerClient->getActiveDisplayMode(dpy, &mode);
     if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::getActiveDisplayConfig failed: %#x\n", err);
+        fprintf(stderr, "SurfaceComposer::getActiveDisplayMode failed: %#x\n", err);
         return false;
     }
 
-    float scaleX = static_cast<float>(config.resolution.getWidth()) / w;
-    float scaleY = static_cast<float>(config.resolution.getHeight()) / h;
+    float scaleX = static_cast<float>(mode.resolution.getWidth()) / w;
+    float scaleY = static_cast<float>(mode.resolution.getHeight()) / h;
     *scale = scaleX < scaleY ? scaleX : scaleY;
 
     return true;
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 72ffc94..1ebdc47 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "idlcli-defaults",
     shared_libs: [
@@ -44,6 +53,8 @@
         "vibrator/CommandGetCompositionDelayMax.cpp",
         "vibrator/CommandGetCompositionSizeMax.cpp",
         "vibrator/CommandGetPrimitiveDuration.cpp",
+        "vibrator/CommandGetQFactor.cpp",
+        "vibrator/CommandGetResonantFrequency.cpp",
         "vibrator/CommandGetSupportedAlwaysOnEffects.cpp",
         "vibrator/CommandGetSupportedEffects.cpp",
         "vibrator/CommandGetSupportedPrimitives.cpp",
diff --git a/cmds/idlcli/vibrator/CommandGetQFactor.cpp b/cmds/idlcli/vibrator/CommandGetQFactor.cpp
new file mode 100644
index 0000000..a2681e9
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetQFactor.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetQFactor : public Command {
+    std::string getDescription() const override { return "Retrieves vibrator Q factor."; }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        float qFactor;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getQFactor, &qFactor);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Q Factor: " << qFactor << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetQFactor>("getQFactor");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp b/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp
new file mode 100644
index 0000000..81a6391
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetResonantFrequency : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator resonant frequency in Hz.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        float resonantFrequencyHz;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getResonantFrequency, &resonantFrequencyHz);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Resonant Frequency: " << resonantFrequencyHz << " Hz" << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandGetResonantFrequency>(
+    "getResonantFrequency");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index cbe857a..5c2211f 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "installd_defaults",
 
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 7c9e3b2..f67ab81 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -1,4 +1,13 @@
 // Build the unit tests for installd
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "installd_utils_test",
     test_suites: ["device-tests"],
@@ -157,4 +166,3 @@
         "libotapreoptparameters"
     ],
 }
-
diff --git a/cmds/ip-up-vpn/Android.mk b/cmds/ip-up-vpn/Android.mk
index e1e2204..396ae9d 100644
--- a/cmds/ip-up-vpn/Android.mk
+++ b/cmds/ip-up-vpn/Android.mk
@@ -21,6 +21,9 @@
 LOCAL_CFLAGS := -Wall -Werror
 LOCAL_SHARED_LIBRARIES := libcutils liblog
 LOCAL_MODULE := ip-up-vpn
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/ppp
 LOCAL_MODULE_TAGS := optional
 
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 0cbb80f..649e53a 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
     name: "liblshal",
     shared_libs: [
diff --git a/cmds/lshal/libprocpartition/Android.bp b/cmds/lshal/libprocpartition/Android.bp
index 9592111..cbfbdc9 100644
--- a/cmds/lshal/libprocpartition/Android.bp
+++ b/cmds/lshal/libprocpartition/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
     name: "libprocpartition",
     shared_libs: [
diff --git a/cmds/rawbu/Android.bp b/cmds/rawbu/Android.bp
index 363ffc1..e34119d 100644
--- a/cmds/rawbu/Android.bp
+++ b/cmds/rawbu/Android.bp
@@ -1,5 +1,22 @@
 // Copyright 2009 The Android Open Source Project
 
+package {
+    default_applicable_licenses: ["frameworks_native_cmds_rawbu_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_cmds_rawbu_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_binary {
     name: "rawbu",
 
diff --git a/cmds/rss_hwm_reset/Android.bp b/cmds/rss_hwm_reset/Android.bp
index 15f10ef..cd335d4 100644
--- a/cmds/rss_hwm_reset/Android.bp
+++ b/cmds/rss_hwm_reset/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "rss_hwm_reset",
 
diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp
index a5b1ac5..3e8e3f6 100644
--- a/cmds/service/Android.bp
+++ b/cmds/service/Android.bp
@@ -1,3 +1,20 @@
+package {
+    default_applicable_licenses: ["frameworks_native_cmds_service_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_cmds_service_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_binary {
     name: "service",
 
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index b139251..9de344a 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "servicemanager_defaults",
 
diff --git a/cmds/surfacereplayer/Android.bp b/cmds/surfacereplayer/Android.bp
index d4c037a..34fc8b1 100644
--- a/cmds/surfacereplayer/Android.bp
+++ b/cmds/surfacereplayer/Android.bp
@@ -1,4 +1,13 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 subdirs = [
     "proto",
     "replayer",
-]
\ No newline at end of file
+]
diff --git a/cmds/surfacereplayer/proto/Android.bp b/cmds/surfacereplayer/proto/Android.bp
index 71a5e23..dae976e 100644
--- a/cmds/surfacereplayer/proto/Android.bp
+++ b/cmds/surfacereplayer/proto/Android.bp
@@ -1,3 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
     name: "libtrace_proto",
     srcs: [
diff --git a/cmds/surfacereplayer/replayer/Android.bp b/cmds/surfacereplayer/replayer/Android.bp
index 7632311..3985230 100644
--- a/cmds/surfacereplayer/replayer/Android.bp
+++ b/cmds/surfacereplayer/replayer/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libsurfacereplayer",
     srcs: [
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 58d6582..3c53c02 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -28,7 +28,6 @@
 #include <gui/Surface.h>
 #include <private/gui/ComposerService.h>
 
-#include <ui/DisplayInfo.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
 #include <utils/Trace.h>
diff --git a/data/etc/android.hardware.keystore.app_attest_key.xml b/data/etc/android.hardware.keystore.app_attest_key.xml
new file mode 100644
index 0000000..8adc439
--- /dev/null
+++ b/data/etc/android.hardware.keystore.app_attest_key.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices that support app attestation keys (i.e. KeyMint 1.0). -->
+<permissions>
+    <feature name="android.hardware.keystore.app_attest_key" />
+</permissions>
diff --git a/headers/Android.bp b/headers/Android.bp
index 8f41c2b..7481a23 100644
--- a/headers/Android.bp
+++ b/headers/Android.bp
@@ -1,3 +1,13 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_headers {
     name: "media_plugin_headers",
     vendor_available: true,
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/android/permission_manager.h b/include/android/permission_manager.h
index 2d5d060..753b6d1 100644
--- a/include/android/permission_manager.h
+++ b/include/android/permission_manager.h
@@ -14,6 +14,17 @@
  * limitations under the License.
  */
 
+/**
+ * Structures and functions related to permission checks in native code.
+ *
+ * @addtogroup Permission
+ * @{
+ */
+
+/**
+ * @file permission_manager.h
+ */
+
 #ifndef ANDROID_PERMISSION_MANAGER_H
 #define ANDROID_PERMISSION_MANAGER_H
 
@@ -48,8 +59,8 @@
 enum {
     /**
      * This is returned if the permission check completed without errors.
-     * The output result is valid and contains one of {PERMISSION_MANAGER_PERMISSION_GRANTED,
-     * PERMISSION_MANAGER_PERMISSION_DENIED}.
+     * The output result is valid and contains one of {::PERMISSION_MANAGER_PERMISSION_GRANTED,
+     * ::PERMISSION_MANAGER_PERMISSION_DENIED}.
      */
     PERMISSION_MANAGER_STATUS_OK = 0,
     /**
@@ -85,3 +96,5 @@
 __END_DECLS
 
 #endif  // ANDROID_PERMISSION_MANAGER_H
+
+/** @} */
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 98fd875..b836581 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -67,9 +67,21 @@
                                         __INTRODUCED_IN(29);
 
 /**
- * Releases the \a surface_control object. After releasing the ASurfaceControl the caller no longer
- * has ownership of the AsurfaceControl. The surface and it's children may remain on display as long
- * as their parent remains on display.
+ * Acquires a reference on the given ASurfaceControl object.  This prevents the object
+ * from being deleted until the reference is removed.
+ *
+ * To release the reference, use the ASurfaceControl_release function.
+ *
+ * Available since API level 31.
+ */
+void ASurfaceControl_acquire(ASurfaceControl* surface_control) __INTRODUCED_IN(31);
+
+/**
+ * Removes a reference that was previously acquired with one of the following functions:
+ *   ASurfaceControl_createFromWindow
+ *   ASurfaceControl_create
+ *   ANativeWindow_acquire
+ * The surface and its children may remain on display as long as their parent remains on display.
  *
  * Available since API level 29.
  */
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 8744ef7..11b714f 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -30,6 +30,7 @@
  */
 
 #include <string>
+#include <unordered_map>
 
 #include <android-base/chrono_utils.h>
 
@@ -155,6 +156,7 @@
         struct Finished {
             uint32_t empty1;
             uint32_t handled; // actually a bool, but we must maintain 8-byte alignment
+            nsecs_t consumeTime; // The time when the event was consumed by the receiving end
 
             inline size_t size() const { return sizeof(Finished); }
         } finished;
@@ -362,7 +364,8 @@
 
     /* Receives the finished signal from the consumer in reply to the original dispatch signal.
      * If a signal was received, returns the message sequence number,
-     * and whether the consumer handled the message.
+     * whether the consumer handled the message, and the time the event was first read by the
+     * consumer.
      *
      * The returned sequence number is never 0 unless the operation failed.
      *
@@ -371,7 +374,8 @@
      * Returns DEAD_OBJECT if the channel's peer has been closed.
      * Other errors probably indicate that the channel is broken.
      */
-    status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
+    status_t receiveFinishedSignal(
+            const std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)>& callback);
 
 private:
     std::shared_ptr<InputChannel> mChannel;
@@ -577,6 +581,13 @@
     };
     std::vector<SeqChain> mSeqChains;
 
+    // The time at which each event with the sequence number 'seq' was consumed.
+    // This data is provided in 'finishInputEvent' so that the receiving end can measure the latency
+    // This collection is populated when the event is received, and the entries are erased when the
+    // events are finished. It should not grow infinitely because if an event is not ack'd, ANR
+    // will be raised for that connection, and no further events will be posted to that channel.
+    std::unordered_map<uint32_t /*seq*/, nsecs_t /*consumeTime*/> mConsumeTimes;
+
     status_t consumeBatch(InputEventFactoryInterface* factory,
             nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
     status_t consumeSamples(InputEventFactoryInterface* factory,
@@ -589,6 +600,8 @@
     ssize_t findBatch(int32_t deviceId, int32_t source) const;
     ssize_t findTouchState(int32_t deviceId, int32_t source) const;
 
+    nsecs_t getConsumeTime(uint32_t seq) const;
+    void popConsumeTime(uint32_t seq);
     status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
 
     static void rewriteMessage(TouchState& state, InputMessage& msg);
diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h
index 4fa2f86..eda628e 100644
--- a/include/input/TouchVideoFrame.h
+++ b/include/input/TouchVideoFrame.h
@@ -57,7 +57,7 @@
 
     /**
      * Rotate the video frame.
-     * The rotation value is an enum from ui/DisplayInfo.h
+     * The rotation value is an enum from ui/Rotation.h
      */
     void rotate(int32_t orientation);
 
diff --git a/include/private/surface_control_private.h b/include/private/surface_control_private.h
new file mode 100644
index 0000000..37a476e
--- /dev/null
+++ b/include/private/surface_control_private.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_PRIVATE_NATIVE_SURFACE_CONTROL_H
+#define ANDROID_PRIVATE_NATIVE_SURFACE_CONTROL_H
+
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+struct ASurfaceControl;
+struct ASurfaceControlStats;
+
+typedef struct ASurfaceControlStats ASurfaceControlStats;
+
+/**
+ * Callback to be notified when surface stats for a specific surface control are available.
+ */
+typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context,
+        ASurfaceControl* control, ASurfaceControlStats* stats);
+
+/**
+ * Registers a callback to be invoked when surface stats from a specific surface are available.
+ *
+ * \param context Optional context provided by the client that is passed into
+ * the callback.
+ *
+ * \param control The surface to retrieve callbacks for.
+ *
+ * \param func The callback to be invoked when surface stats are available.
+ */
+void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, void* context,
+        ASurfaceControl_SurfaceStatsListener func);
+
+/**
+ * Unregisters a callback to be invoked when surface stats from a specific surface are available.
+ *
+ * \param context The context passed into ASurfaceControl_registerSurfaceStatsListener
+ *
+ * \param func The callback passed into ASurfaceControl_registerSurfaceStatsListener
+ */
+void ASurfaceControl_unregisterSurfaceStatsListener(void* context,
+                                       ASurfaceControl_SurfaceStatsListener func);
+
+/**
+ * Returns the timestamp of when the buffer was acquired for a specific frame with frame number
+ * obtained from ASurfaceControlStats_getFrameNumber.
+ */
+int64_t ASurfaceControlStats_getAcquireTime(ASurfaceControlStats* stats);
+
+/**
+ * Returns the frame number of the surface stats object passed into the callback.
+ */
+uint64_t ASurfaceControlStats_getFrameNumber(ASurfaceControlStats* stats);
+
+__END_DECLS
+
+#endif //ANDROID_PRIVATE_NATIVE_SURFACE_CONTROL_H
diff --git a/include/ui/DisplayInfo.h b/include/ui/DisplayInfo.h
deleted file mode 120000
index 9a195ea..0000000
--- a/include/ui/DisplayInfo.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/ui/include/ui/DisplayInfo.h
\ No newline at end of file
diff --git a/include/ui/StaticDisplayInfo.h b/include/ui/StaticDisplayInfo.h
new file mode 120000
index 0000000..c58aae3
--- /dev/null
+++ b/include/ui/StaticDisplayInfo.h
@@ -0,0 +1 @@
+../../libs/ui/include/ui/StaticDisplayInfo.h
\ No newline at end of file
diff --git a/libs/adbd_auth/Android.bp b/libs/adbd_auth/Android.bp
index 8883c04..16cded8 100644
--- a/libs/adbd_auth/Android.bp
+++ b/libs/adbd_auth/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library {
     name: "libadbd_auth",
     cflags: [
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
index cdd7764..b74923c 100644
--- a/libs/android_runtime_lazy/Android.bp
+++ b/libs/android_runtime_lazy/Android.bp
@@ -30,6 +30,15 @@
 // instead of libandroid_runtime. When they are used by a vendor process,
 // depending on libandroid_runtime is meaningless. In this case,
 // they can depend on libandroid_runtime_lazy.
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library {
     name: "libandroid_runtime_lazy",
     vendor_available: true,
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 80aa891..bb40f51 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -12,6 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["frameworks_native_libs_arect_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_libs_arect_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 ndk_headers {
     name: "libarect_headers_for_ndk",
     from: "include/android",
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b585ad2..e9d866b 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_headers {
     name: "libbinder_headers",
     export_include_dirs: ["include"],
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index bf4387a..ddda024 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -228,8 +228,9 @@
                 : Stability::getLocalLevel();
 
             if (CC_UNLIKELY(!Stability::check(category, required))) {
-                ALOGE("Cannot do a user transaction on a %s binder in a %s context.",
+                ALOGE("Cannot do a user transaction on a %s binder (%s) in a %s context.",
                     category.debugString().c_str(),
+                    String8(getInterfaceDescriptor()).c_str(),
                     Stability::levelString(required).c_str());
                 return BAD_TYPE;
             }
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b9d00fe..3773760 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -520,7 +520,7 @@
     }
 }
 
-#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID_VNDK__)
 constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
 #else
 constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
@@ -769,200 +769,116 @@
     return NO_ERROR;
 }
 
-status_t Parcel::writeUtf8AsUtf16(const std::optional<std::string>& str) {
-  if (!str) {
-    return writeInt32(-1);
-  }
-  return writeUtf8AsUtf16(*str);
-}
 
-status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) {
-  if (!str) {
-    return writeInt32(-1);
-  }
-  return writeUtf8AsUtf16(*str);
-}
+status_t Parcel::writeUtf8AsUtf16(const std::optional<std::string>& str) { return writeData(str); }
+status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) { return writeData(str); }
 
-status_t Parcel::writeByteVectorInternal(const int8_t* data, size_t size) {
-    if (size > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
+status_t Parcel::writeString16(const std::optional<String16>& str) { return writeData(str); }
+status_t Parcel::writeString16(const std::unique_ptr<String16>& str) { return writeData(str); }
 
-    status_t status = writeInt32(size);
-    if (status != OK) {
-        return status;
-    }
+status_t Parcel::writeByteVector(const std::vector<int8_t>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::optional<std::vector<int8_t>>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::vector<uint8_t>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::optional<std::vector<uint8_t>>& val) { return writeData(val); }
+status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val){ return writeData(val); }
+status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val) { return writeData(val); }
+status_t Parcel::writeInt32Vector(const std::optional<std::vector<int32_t>>& val) { return writeData(val); }
+status_t Parcel::writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val) { return writeData(val); }
+status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val) { return writeData(val); }
+status_t Parcel::writeInt64Vector(const std::optional<std::vector<int64_t>>& val) { return writeData(val); }
+status_t Parcel::writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val) { return writeData(val); }
+status_t Parcel::writeUint64Vector(const std::vector<uint64_t>& val) { return writeData(val); }
+status_t Parcel::writeUint64Vector(const std::optional<std::vector<uint64_t>>& val) { return writeData(val); }
+status_t Parcel::writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val) { return writeData(val); }
+status_t Parcel::writeFloatVector(const std::vector<float>& val) { return writeData(val); }
+status_t Parcel::writeFloatVector(const std::optional<std::vector<float>>& val) { return writeData(val); }
+status_t Parcel::writeFloatVector(const std::unique_ptr<std::vector<float>>& val) { return writeData(val); }
+status_t Parcel::writeDoubleVector(const std::vector<double>& val) { return writeData(val); }
+status_t Parcel::writeDoubleVector(const std::optional<std::vector<double>>& val) { return writeData(val); }
+status_t Parcel::writeDoubleVector(const std::unique_ptr<std::vector<double>>& val) { return writeData(val); }
+status_t Parcel::writeBoolVector(const std::vector<bool>& val) { return writeData(val); }
+status_t Parcel::writeBoolVector(const std::optional<std::vector<bool>>& val) { return writeData(val); }
+status_t Parcel::writeBoolVector(const std::unique_ptr<std::vector<bool>>& val) { return writeData(val); }
+status_t Parcel::writeCharVector(const std::vector<char16_t>& val) { return writeData(val); }
+status_t Parcel::writeCharVector(const std::optional<std::vector<char16_t>>& val) { return writeData(val); }
+status_t Parcel::writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val) { return writeData(val); }
 
-    return write(data, size);
-}
-
-status_t Parcel::writeByteVector(const std::vector<int8_t>& val) {
-    return writeByteVectorInternal(val.data(), val.size());
-}
-
-status_t Parcel::writeByteVector(const std::optional<std::vector<int8_t>>& val)
-{
-    if (!val) return writeInt32(-1);
-    return writeByteVectorInternal(val->data(), val->size());
-}
-
-status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val)
-{
-    if (!val) return writeInt32(-1);
-    return writeByteVectorInternal(val->data(), val->size());
-}
-
-status_t Parcel::writeByteVector(const std::vector<uint8_t>& val) {
-    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
-}
-
-status_t Parcel::writeByteVector(const std::optional<std::vector<uint8_t>>& val)
-{
-    if (!val) return writeInt32(-1);
-    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-
-status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val)
-{
-    if (!val) return writeInt32(-1);
-    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-
-status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val)
-{
-    return writeTypedVector(val, &Parcel::writeInt32);
-}
-
-status_t Parcel::writeInt32Vector(const std::optional<std::vector<int32_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeInt32);
-}
-
-status_t Parcel::writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeInt32);
-}
-
-status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val)
-{
-    return writeTypedVector(val, &Parcel::writeInt64);
-}
-
-status_t Parcel::writeInt64Vector(const std::optional<std::vector<int64_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeInt64);
-}
-
-status_t Parcel::writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeInt64);
-}
-
-status_t Parcel::writeUint64Vector(const std::vector<uint64_t>& val)
-{
-    return writeTypedVector(val, &Parcel::writeUint64);
-}
-
-status_t Parcel::writeUint64Vector(const std::optional<std::vector<uint64_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeUint64);
-}
-
-status_t Parcel::writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeUint64);
-}
-
-status_t Parcel::writeFloatVector(const std::vector<float>& val)
-{
-    return writeTypedVector(val, &Parcel::writeFloat);
-}
-
-status_t Parcel::writeFloatVector(const std::optional<std::vector<float>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeFloat);
-}
-
-status_t Parcel::writeFloatVector(const std::unique_ptr<std::vector<float>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeFloat);
-}
-
-status_t Parcel::writeDoubleVector(const std::vector<double>& val)
-{
-    return writeTypedVector(val, &Parcel::writeDouble);
-}
-
-status_t Parcel::writeDoubleVector(const std::optional<std::vector<double>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeDouble);
-}
-
-status_t Parcel::writeDoubleVector(const std::unique_ptr<std::vector<double>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeDouble);
-}
-
-status_t Parcel::writeBoolVector(const std::vector<bool>& val)
-{
-    return writeTypedVector(val, &Parcel::writeBool);
-}
-
-status_t Parcel::writeBoolVector(const std::optional<std::vector<bool>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeBool);
-}
-
-status_t Parcel::writeBoolVector(const std::unique_ptr<std::vector<bool>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeBool);
-}
-
-status_t Parcel::writeCharVector(const std::vector<char16_t>& val)
-{
-    return writeTypedVector(val, &Parcel::writeChar);
-}
-
-status_t Parcel::writeCharVector(const std::optional<std::vector<char16_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeChar);
-}
-
-status_t Parcel::writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeChar);
-}
-
-status_t Parcel::writeString16Vector(const std::vector<String16>& val)
-{
-    return writeTypedVector(val, &Parcel::writeString16);
-}
-
+status_t Parcel::writeString16Vector(const std::vector<String16>& val) { return writeData(val); }
 status_t Parcel::writeString16Vector(
-        const std::optional<std::vector<std::optional<String16>>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeString16);
-}
-
+        const std::optional<std::vector<std::optional<String16>>>& val) { return writeData(val); }
 status_t Parcel::writeString16Vector(
-        const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeString16);
-}
-
+        const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val) { return writeData(val); }
 status_t Parcel::writeUtf8VectorAsUtf16Vector(
-                        const std::optional<std::vector<std::optional<std::string>>>& val) {
-    return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16);
-}
-
+                        const std::optional<std::vector<std::optional<std::string>>>& val) { return writeData(val); }
 status_t Parcel::writeUtf8VectorAsUtf16Vector(
-                        const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) {
-    return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16);
-}
+                        const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) { return writeData(val); }
+status_t Parcel::writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val) { return writeData(val); }
 
-status_t Parcel::writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val) {
-    return writeTypedVector(val, &Parcel::writeUtf8AsUtf16);
-}
+status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<base::unique_fd>& val) { return writeData(val); }
+status_t Parcel::writeUniqueFileDescriptorVector(const std::optional<std::vector<base::unique_fd>>& val) { return writeData(val); }
+status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<base::unique_fd>>& val) { return writeData(val); }
+
+status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val) { return writeData(val); }
+status_t Parcel::writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val) { return writeData(val); }
+status_t Parcel::writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val) { return writeData(val); }
+
+status_t Parcel::writeParcelable(const Parcelable& parcelable) { return writeData(parcelable); }
+
+status_t Parcel::readUtf8FromUtf16(std::optional<std::string>* str) const { return readData(str); }
+status_t Parcel::readUtf8FromUtf16(std::unique_ptr<std::string>* str) const { return readData(str); }
+
+status_t Parcel::readString16(std::optional<String16>* pArg) const { return readData(pArg); }
+status_t Parcel::readString16(std::unique_ptr<String16>* pArg) const { return readData(pArg); }
+
+status_t Parcel::readByteVector(std::vector<int8_t>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::vector<uint8_t>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::optional<std::vector<int8_t>>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::optional<std::vector<uint8_t>>* val) const { return readData(val); }
+status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const { return readData(val); }
+status_t Parcel::readInt32Vector(std::optional<std::vector<int32_t>>* val) const { return readData(val); }
+status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const { return readData(val); }
+status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const { return readData(val); }
+status_t Parcel::readInt64Vector(std::optional<std::vector<int64_t>>* val) const { return readData(val); }
+status_t Parcel::readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const { return readData(val); }
+status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const { return readData(val); }
+status_t Parcel::readUint64Vector(std::optional<std::vector<uint64_t>>* val) const { return readData(val); }
+status_t Parcel::readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const { return readData(val); }
+status_t Parcel::readUint64Vector(std::vector<uint64_t>* val) const { return readData(val); }
+status_t Parcel::readFloatVector(std::optional<std::vector<float>>* val) const { return readData(val); }
+status_t Parcel::readFloatVector(std::unique_ptr<std::vector<float>>* val) const { return readData(val); }
+status_t Parcel::readFloatVector(std::vector<float>* val) const { return readData(val); }
+status_t Parcel::readDoubleVector(std::optional<std::vector<double>>* val) const { return readData(val); }
+status_t Parcel::readDoubleVector(std::unique_ptr<std::vector<double>>* val) const { return readData(val); }
+status_t Parcel::readDoubleVector(std::vector<double>* val) const { return readData(val); }
+status_t Parcel::readBoolVector(std::optional<std::vector<bool>>* val) const { return readData(val); }
+status_t Parcel::readBoolVector(std::unique_ptr<std::vector<bool>>* val) const { return readData(val); }
+status_t Parcel::readBoolVector(std::vector<bool>* val) const { return readData(val); }
+status_t Parcel::readCharVector(std::optional<std::vector<char16_t>>* val) const { return readData(val); }
+status_t Parcel::readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const { return readData(val); }
+status_t Parcel::readCharVector(std::vector<char16_t>* val) const { return readData(val); }
+
+status_t Parcel::readString16Vector(
+        std::optional<std::vector<std::optional<String16>>>* val) const { return readData(val); }
+status_t Parcel::readString16Vector(
+        std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const { return readData(val); }
+status_t Parcel::readString16Vector(std::vector<String16>* val) const { return readData(val); }
+status_t Parcel::readUtf8VectorFromUtf16Vector(
+        std::optional<std::vector<std::optional<std::string>>>* val) const { return readData(val); }
+status_t Parcel::readUtf8VectorFromUtf16Vector(
+        std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const { return readData(val); }
+status_t Parcel::readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const { return readData(val); }
+
+status_t Parcel::readUniqueFileDescriptorVector(std::optional<std::vector<base::unique_fd>>* val) const { return readData(val); }
+status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const { return readData(val); }
+status_t Parcel::readUniqueFileDescriptorVector(std::vector<base::unique_fd>* val) const { return readData(val); }
+
+status_t Parcel::readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const { return readData(val); }
+status_t Parcel::readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const { return readData(val); }
+status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const { return readData(val); }
+
+status_t Parcel::readParcelable(Parcelable* parcelable) const { return readData(parcelable); }
 
 status_t Parcel::writeInt32(int32_t val)
 {
@@ -1091,24 +1007,6 @@
     return err;
 }
 
-status_t Parcel::writeString16(const std::optional<String16>& str)
-{
-    if (!str) {
-        return writeInt32(-1);
-    }
-
-    return writeString16(*str);
-}
-
-status_t Parcel::writeString16(const std::unique_ptr<String16>& str)
-{
-    if (!str) {
-        return writeInt32(-1);
-    }
-
-    return writeString16(*str);
-}
-
 status_t Parcel::writeString16(const String16& str)
 {
     return writeString16(str.string(), str.size());
@@ -1138,32 +1036,6 @@
     return flattenBinder(val);
 }
 
-status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val)
-{
-    return writeTypedVector(val, &Parcel::writeStrongBinder);
-}
-
-status_t Parcel::writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeStrongBinder);
-}
-
-status_t Parcel::writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val)
-{
-    return writeNullableTypedVector(val, &Parcel::writeStrongBinder);
-}
-
-status_t Parcel::readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readNullableStrongBinder);
-}
-
-status_t Parcel::readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readNullableStrongBinder);
-}
-
-status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const {
-    return readTypedVector(val, &Parcel::readStrongBinder);
-}
 
 status_t Parcel::writeRawNullableParcelable(const Parcelable* parcelable) {
     if (!parcelable) {
@@ -1173,14 +1045,6 @@
     return writeParcelable(*parcelable);
 }
 
-status_t Parcel::writeParcelable(const Parcelable& parcelable) {
-    status_t status = writeInt32(1);  // parcelable is not null.
-    if (status != OK) {
-        return status;
-    }
-    return parcelable.writeToParcel(this);
-}
-
 status_t Parcel::writeNativeHandle(const native_handle* handle)
 {
     if (!handle || handle->version != sizeof(native_handle))
@@ -1251,18 +1115,6 @@
     return writeDupFileDescriptor(fd.get());
 }
 
-status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<base::unique_fd>& val) {
-    return writeTypedVector(val, &Parcel::writeUniqueFileDescriptor);
-}
-
-status_t Parcel::writeUniqueFileDescriptorVector(const std::optional<std::vector<base::unique_fd>>& val) {
-    return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor);
-}
-
-status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<base::unique_fd>>& val) {
-    return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor);
-}
-
 status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob)
 {
     if (len > INT32_MAX) {
@@ -1477,31 +1329,6 @@
     goto data_sorted;
 }
 
-status_t Parcel::readVectorSizeWithCoarseBoundCheck(int32_t *size) const {
-    int32_t requestedSize;
-    const status_t status = readInt32(&requestedSize);
-    if (status != NO_ERROR) return status;
-
-    // We permit negative sizes, which indicate presence of a nullable vector,
-    // i.e. a vector embedded in std::optional, std::unique_ptr, or std::shared_ptr.
-    if (requestedSize > 0) {
-        // Check if there are fewer bytes than vector elements.
-        // A lower bound is 1 byte per element, satisfied by some enum and int8_t and uint8_t.
-        const size_t availableBytes = dataAvail();
-        if (static_cast<size_t>(requestedSize) > availableBytes) {
-            // We have a size that is greater than the number of bytes available.
-            // On bounds failure we do not 'rewind' position by 4 bytes of the size already read.
-            ALOGW("%s: rejecting out of bounds vector size (requestedSize):%d "
-                    "Parcel{dataAvail:%zu mDataSize:%zu mDataPos:%zu mDataCapacity:%zu}",
-                    __func__, requestedSize, availableBytes, mDataSize, mDataPos, mDataCapacity);
-            return BAD_VALUE;
-        }
-    }
-
-    *size = requestedSize;
-    return NO_ERROR;
-}
-
 status_t Parcel::read(void* outData, size_t len) const
 {
     if (len > INT32_MAX) {
@@ -1605,236 +1432,6 @@
     return err;
 }
 
-status_t Parcel::readByteVector(std::vector<int8_t>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    return readByteVectorInternal(val, size);
-}
-
-status_t Parcel::readByteVector(std::vector<uint8_t>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    return readByteVectorInternal(val, size);
-}
-
-status_t Parcel::readByteVector(std::optional<std::vector<int8_t>>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    if (!*val) {
-        // reserveOutVector does not create the out vector if size is < 0.
-        // This occurs when writing a null byte vector.
-        return OK;
-    }
-    return readByteVectorInternal(&**val, size);
-}
-
-status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    if (val->get() == nullptr) {
-        // reserveOutVector does not create the out vector if size is < 0.
-        // This occurs when writing a null byte vector.
-        return OK;
-    }
-    return readByteVectorInternal(val->get(), size);
-}
-
-status_t Parcel::readByteVector(std::optional<std::vector<uint8_t>>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    if (!*val) {
-        // reserveOutVector does not create the out vector if size is < 0.
-        // This occurs when writing a null byte vector.
-        return OK;
-    }
-    return readByteVectorInternal(&**val, size);
-}
-
-status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    if (val->get() == nullptr) {
-        // reserveOutVector does not create the out vector if size is < 0.
-        // This occurs when writing a null byte vector.
-        return OK;
-    }
-    return readByteVectorInternal(val->get(), size);
-}
-
-status_t Parcel::readInt32Vector(std::optional<std::vector<int32_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readInt32);
-}
-
-status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readInt32);
-}
-
-status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const {
-    return readTypedVector(val, &Parcel::readInt32);
-}
-
-status_t Parcel::readInt64Vector(std::optional<std::vector<int64_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readInt64);
-}
-
-status_t Parcel::readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readInt64);
-}
-
-status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const {
-    return readTypedVector(val, &Parcel::readInt64);
-}
-
-status_t Parcel::readUint64Vector(std::optional<std::vector<uint64_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readUint64);
-}
-
-status_t Parcel::readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readUint64);
-}
-
-status_t Parcel::readUint64Vector(std::vector<uint64_t>* val) const {
-    return readTypedVector(val, &Parcel::readUint64);
-}
-
-status_t Parcel::readFloatVector(std::optional<std::vector<float>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readFloat);
-}
-
-status_t Parcel::readFloatVector(std::unique_ptr<std::vector<float>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readFloat);
-}
-
-status_t Parcel::readFloatVector(std::vector<float>* val) const {
-    return readTypedVector(val, &Parcel::readFloat);
-}
-
-status_t Parcel::readDoubleVector(std::optional<std::vector<double>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readDouble);
-}
-
-status_t Parcel::readDoubleVector(std::unique_ptr<std::vector<double>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readDouble);
-}
-
-status_t Parcel::readDoubleVector(std::vector<double>* val) const {
-    return readTypedVector(val, &Parcel::readDouble);
-}
-
-status_t Parcel::readBoolVector(std::optional<std::vector<bool>>* val) const {
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->emplace();
-
-    status = readBoolVector(&**val);
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-status_t Parcel::readBoolVector(std::unique_ptr<std::vector<bool>>* val) const {
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->reset(new (std::nothrow) std::vector<bool>());
-
-    status = readBoolVector(val->get());
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-status_t Parcel::readBoolVector(std::vector<bool>* val) const {
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        return UNEXPECTED_NULL;
-    }
-
-    val->resize(size);
-
-    /* C++ bool handling means a vector of bools isn't necessarily addressable
-     * (we might use individual bits)
-     */
-    bool data;
-    for (int32_t i = 0; i < size; ++i) {
-        status = readBool(&data);
-        (*val)[i] = data;
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
-}
-
-status_t Parcel::readCharVector(std::optional<std::vector<char16_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readChar);
-}
-
-status_t Parcel::readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readChar);
-}
-
-status_t Parcel::readCharVector(std::vector<char16_t>* val) const {
-    return readTypedVector(val, &Parcel::readChar);
-}
-
-status_t Parcel::readString16Vector(
-        std::optional<std::vector<std::optional<String16>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readString16);
-}
-
-status_t Parcel::readString16Vector(
-        std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readString16);
-}
-
-status_t Parcel::readString16Vector(std::vector<String16>* val) const {
-    return readTypedVector(val, &Parcel::readString16);
-}
-
-status_t Parcel::readUtf8VectorFromUtf16Vector(
-        std::optional<std::vector<std::optional<std::string>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16);
-}
-
-status_t Parcel::readUtf8VectorFromUtf16Vector(
-        std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16);
-}
-
-status_t Parcel::readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const {
-    return readTypedVector(val, &Parcel::readUtf8FromUtf16);
-}
-
 status_t Parcel::readInt32(int32_t *pArg) const
 {
     return readAligned(pArg);
@@ -2007,36 +1604,6 @@
     return NO_ERROR;
 }
 
-status_t Parcel::readUtf8FromUtf16(std::optional<std::string>* str) const {
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readInt32(&size);
-    str->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    str->emplace();
-    return readUtf8FromUtf16(&**str);
-}
-
-status_t Parcel::readUtf8FromUtf16(std::unique_ptr<std::string>* str) const {
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readInt32(&size);
-    str->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    str->reset(new (std::nothrow) std::string());
-    return readUtf8FromUtf16(str->get());
-}
-
 const char* Parcel::readCString() const
 {
     if (mDataPos < mDataSize) {
@@ -2103,51 +1670,6 @@
     return String16();
 }
 
-status_t Parcel::readString16(std::optional<String16>* pArg) const
-{
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readInt32(&size);
-    pArg->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    pArg->emplace();
-
-    status = readString16(&**pArg);
-
-    if (status != OK) {
-        pArg->reset();
-    }
-
-    return status;
-}
-
-status_t Parcel::readString16(std::unique_ptr<String16>* pArg) const
-{
-    const int32_t start = dataPosition();
-    int32_t size;
-    status_t status = readInt32(&size);
-    pArg->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    pArg->reset(new (std::nothrow) String16());
-
-    status = readString16(pArg->get());
-
-    if (status != OK) {
-        pArg->reset();
-    }
-
-    return status;
-}
 
 status_t Parcel::readString16(String16* pArg) const
 {
@@ -2204,18 +1726,6 @@
     return val;
 }
 
-status_t Parcel::readParcelable(Parcelable* parcelable) const {
-    int32_t have_parcelable = 0;
-    status_t status = readInt32(&have_parcelable);
-    if (status != OK) {
-        return status;
-    }
-    if (!have_parcelable) {
-        return UNEXPECTED_NULL;
-    }
-    return parcelable->readFromParcel(this);
-}
-
 int32_t Parcel::readExceptionCode() const
 {
     binder::Status status;
@@ -2334,18 +1844,6 @@
     return OK;
 }
 
-status_t Parcel::readUniqueFileDescriptorVector(std::optional<std::vector<base::unique_fd>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
-}
-
-status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
-}
-
-status_t Parcel::readUniqueFileDescriptorVector(std::vector<base::unique_fd>* val) const {
-    return readTypedVector(val, &Parcel::readUniqueFileDescriptor);
-}
-
 status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const
 {
     int32_t blobType;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index c38249e..edadcd5 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -406,12 +406,6 @@
     , mThreadPoolSeq(1)
     , mCallRestriction(CallRestriction::NONE)
 {
-
-// TODO(b/166468760): enforce in build system
-#if defined(__ANDROID_APEX__)
-    LOG_ALWAYS_FATAL("Cannot use libbinder in APEX (only system.img libbinder) since it is not stable.");
-#endif
-
     if (mDriverFD >= 0) {
         // mmap the binder, providing a chunk of virtual address space to receive transactions.
         mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index 339c538..b56e09f 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -76,18 +76,12 @@
 }
 
 Stability::Level Stability::getLocalLevel() {
+#ifdef __ANDROID_APEX__
+#error APEX can't use libbinder (must use libbinder_ndk)
+#endif
+
 #ifdef __ANDROID_VNDK__
-    #ifdef __ANDROID_APEX__
-        // TODO(b/142684679) avoid use_vendor on system APEXes
-        #if !defined(__ANDROID_APEX_COM_ANDROID_MEDIA_SWCODEC__) \
-            && !defined(__ANDROID_APEX_TEST_COM_ANDROID_MEDIA_SWCODEC__)
-        #error VNDK + APEX only defined for com.android.media.swcodec
-        #endif
-        // TODO(b/142684679) avoid use_vendor on system APEXes
-        return Level::SYSTEM;
-    #else
-        return Level::VENDOR;
-    #endif
+    return Level::VENDOR;
 #else
     // TODO(b/139325195): split up stability levels for system/APEX.
     return Level::SYSTEM;
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index dc8d74c..a7a6563 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -101,4 +101,17 @@
      * This does nothing if this observer was not already registered.
      */
     void unregisterPackageChangeObserver(in IPackageChangeObserver observer);
+
+    /**
+     * Returns true if the package has the SHA 256 version of the signing certificate.
+     * @see PackageManager#hasSigningCertificate(String, byte[], int), where type
+     * has been set to {@link PackageManager#CERT_INPUT_SHA256}.
+     */
+    boolean hasSha256SigningCertificate(in @utf8InCpp String packageName, in byte[] certificate);
+
+    /**
+     * Returns the debug flag for the given package.
+     * Unknown packages will cause the call to fail.
+     */
+     boolean isPackageDebuggable(in String packageName);
 }
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index ce30050..2fabf94 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -43,9 +43,9 @@
      */
     const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3;
 
-    const int DUMP_FLAG_PRIORITY_ALL = 15;
-             // DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
-             // | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
+    const int DUMP_FLAG_PRIORITY_ALL =
+             DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
+             | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
 
     /* Allows services to dump sections in protobuf format. */
     const int DUMP_FLAG_PROTO = 1 << 4;
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 54c49e4..7b298f5 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -190,34 +190,47 @@
     // Write an Enum vector with underlying type int8_t.
     // Does not use padding; each byte is contiguous.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::vector<T>& val);
+    status_t            writeEnumVector(const std::vector<T>& val)
+            { return writeData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::optional<std::vector<T>>& val);
+    status_t            writeEnumVector(const std::optional<std::vector<T>>& val)
+            { return writeData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
+    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")))
+            { return writeData(val); }
     // Write an Enum vector with underlying type != int8_t.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::vector<T>& val);
+    status_t            writeEnumVector(const std::vector<T>& val)
+            { return writeData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::optional<std::vector<T>>& val);
+    status_t            writeEnumVector(const std::optional<std::vector<T>>& val)
+            { return writeData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
+    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")))
+            { return writeData(val); }
 
     template<typename T>
-    status_t            writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val);
+    status_t            writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val)
+            { return writeData(val); }
     template<typename T>
-    status_t            writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")));
+    status_t            writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")))
+            { return writeData(val); }
     template<typename T>
-    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")));
+    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")))
+            { return writeData(val); }
     template<typename T>
-    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val);
+    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val)
+            { return writeData(val); }
     template<typename T>
-    status_t            writeParcelableVector(const std::vector<T>& val);
+    status_t            writeParcelableVector(const std::vector<T>& val)
+            { return writeData(val); }
 
     template<typename T>
-    status_t            writeNullableParcelable(const std::optional<T>& parcelable);
+    status_t            writeNullableParcelable(const std::optional<T>& parcelable)
+            { return writeData(parcelable); }
     template<typename T>
-    status_t            writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")));
+    status_t            writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")))
+            { return writeData(parcelable); }
 
     status_t            writeParcelable(const Parcelable& parcelable);
 
@@ -335,35 +348,48 @@
     // Read an Enum vector with underlying type int8_t.
     // Does not use padding; each byte is contiguous.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::vector<T>* val) const;
+    status_t            readEnumVector(std::vector<T>* val) const
+            { return readData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
+    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")))
+            { return readData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::optional<std::vector<T>>* val) const;
+    status_t            readEnumVector(std::optional<std::vector<T>>* val) const
+            { return readData(val); }
     // Read an Enum vector with underlying type != int8_t.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::vector<T>* val) const;
+    status_t            readEnumVector(std::vector<T>* val) const
+            { return readData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
+    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")))
+            { return readData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::optional<std::vector<T>>* val) const;
+    status_t            readEnumVector(std::optional<std::vector<T>>* val) const
+            { return readData(val); }
 
     template<typename T>
     status_t            readParcelableVector(
-                            std::optional<std::vector<std::optional<T>>>* val) const;
+                            std::optional<std::vector<std::optional<T>>>* val) const
+            { return readData(val); }
     template<typename T>
     status_t            readParcelableVector(
-                            std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const __attribute__((deprecated("use std::optional version instead")));
+                            std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const __attribute__((deprecated("use std::optional version instead")))
+            { return readData(val); }
     template<typename T>
-    status_t            readParcelableVector(std::vector<T>* val) const;
+    status_t            readParcelableVector(std::vector<T>* val) const
+            { return readData(val); }
 
     status_t            readParcelable(Parcelable* parcelable) const;
 
     template<typename T>
-    status_t            readParcelable(std::optional<T>* parcelable) const;
+    status_t            readParcelable(std::optional<T>* parcelable) const
+            { return readData(parcelable); }
     template<typename T>
-    status_t            readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")));
+    status_t            readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")))
+            { return readData(parcelable); }
 
+    // If strong binder would be nullptr, readStrongBinder() returns an error.
+    // TODO: T must be derived from IInterface, fix for clarity.
     template<typename T>
     status_t            readStrongBinder(sp<T>* val) const;
 
@@ -418,20 +444,13 @@
     template<typename T>
     status_t            read(LightFlattenable<T>& val) const;
 
+    // resizeOutVector is used to resize AIDL out vector parameters.
     template<typename T>
     status_t            resizeOutVector(std::vector<T>* val) const;
     template<typename T>
     status_t            resizeOutVector(std::optional<std::vector<T>>* val) const;
     template<typename T>
     status_t            resizeOutVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
-    template<typename T>
-    status_t            reserveOutVector(std::vector<T>* val, size_t* size) const;
-    template<typename T>
-    status_t            reserveOutVector(std::optional<std::vector<T>>* val,
-                                         size_t* size) const;
-    template<typename T>
-    status_t            reserveOutVector(std::unique_ptr<std::vector<T>>* val,
-                                         size_t* size) const __attribute__((deprecated("use std::optional version instead")));
 
     // Like Parcel.java's readExceptionCode().  Reads the first int32
     // off of a Parcel's header, returning 0 or the negative error
@@ -518,10 +537,6 @@
     void                scanForFds() const;
     status_t            validateReadData(size_t len) const;
 
-    // Reads an int32 size and does a coarse bounds check against the number
-    // of available bytes in the Parcel.
-    status_t            readVectorSizeWithCoarseBoundCheck(int32_t *size) const;
-
     void                updateWorkSourceRequestHeaderPosition() const;
 
     status_t            finishFlattenBinder(const sp<IBinder>& binder);
@@ -540,53 +555,544 @@
     status_t            writeRawNullableParcelable(const Parcelable*
                                                    parcelable);
 
-    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0>
-    status_t            writeEnum(const T& val);
-    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0>
-    status_t            writeEnum(const T& val);
+    //-----------------------------------------------------------------------------
+    // Generic type read and write methods for Parcel:
+    //
+    // readData(T *value) will read a value from the Parcel.
+    // writeData(const T& value) will write a value to the Parcel.
+    //
+    // Our approach to parceling is based on two overloaded functions
+    // readData() and writeData() that generate parceling code for an
+    // object automatically based on its type. The code from templates are generated at
+    // compile time (if constexpr), and decomposes an object through a call graph matching
+    // recursive descent of the template typename.
+    //
+    // This approach unifies handling of complex objects,
+    // resulting in fewer lines of code, greater consistency,
+    // extensibility to nested types, efficiency (decisions made at compile time),
+    // and better code maintainability and optimization.
+    //
+    // Design decision: Incorporate the read and write code into Parcel rather than
+    // as a non-intrusive serializer that emits a byte stream, as we have
+    // active objects, alignment, legacy code, and historical idiosyncrasies.
+    //
+    // --- Overview
+    //
+    // Parceling is a way of serializing objects into a sequence of bytes for communication
+    // between processes, as part of marshaling data for remote procedure calls.
+    //
+    // The Parcel instance contains objects serialized as bytes, such as the following:
+    //
+    // 1) Ordinary primitive data such as int, float.
+    // 2) Established structured data such as String16, std::string.
+    // 3) Parcelables, which are C++ objects that derive from Parcelable (and thus have a
+    //    readFromParcel and writeToParcel method).  (Similar for Java)
+    // 4) A std::vector<> of such data.
+    // 5) Nullable objects contained in std::optional, std::unique_ptr, or std::shared_ptr.
+    //
+    // And active objects from the Android ecosystem such as:
+    // 6) File descriptors, base::unique_fd (kernel object handles)
+    // 7) Binder objects, sp<IBinder> (active Android RPC handles)
+    //
+    // Objects from (1) through (5) serialize into the mData buffer.
+    // Active objects (6) and (7) serialize into both mData and mObjects buffers.
+    //
+    // --- Data layout details
+    //
+    // Data is read or written to the parcel by recursively decomposing the type of the parameter
+    // type T through readData() and writeData() methods.
+    //
+    // We focus on writeData() here in our explanation of the data layout.
+    //
+    // 1) Alignment
+    // Implementation detail: Regardless of the parameter type, writeData() calls are designed
+    // to finish at a multiple of 4 bytes, the default alignment of the Parcel.
+    //
+    // Writes of single uint8_t, int8_t, enums based on types of size 1, char16_t, etc
+    // will result in 4 bytes being written.  The data is widened to int32 and then written;
+    // hence the position of the nonzero bytes depend on the native endianness of the CPU.
+    //
+    // Writes of primitive values with 8 byte size, double, int64_t, uint64_t,
+    // are stored with 4 byte alignment.  The ARM and x86/x64 permit unaligned reads
+    // and writes (albeit with potential latency/throughput penalty) which may or may
+    // not be observable unless the process is IO bound.
+    //
+    // 2) Parcelables
+    // Parcelables are detected by the type's base class, and implemented through calling
+    // into the Parcelable type's readFromParcel() or writeToParcel() methods.
+    // Historically, due to null object detection, a (int32_t) 1 is prepended to the data written.
+    // Parcelables must have a default constructor (i.e. one that takes no arguments).
+    //
+    // 3) Arrays
+    // Arrays of uint8_t and int8_t, and enums based on size 1 are written as
+    // a contiguous packed byte stream.  Hidden zero padding is applied at the end of the byte
+    // stream to make a multiple of 4 bytes (and prevent info leakage when writing).
+    //
+    // All other array writes can be conceptually thought of as recursively calling
+    // writeData on the individual elements (though may be implemented differently for speed).
+    // As discussed in (1), alignment rules are therefore applied for each element
+    // write (not as an aggregate whole), so the wire representation of data can be
+    // substantially larger.
+    //
+    // Historical Note:
+    // Because of element-wise alignment, CharVector and BoolVector are expanded
+    // element-wise into integers even though they could have been optimized to be packed
+    // just like uint8_t, int8_t (size 1 data).
+    //
+    // 3.1) Arrays accessed by the std::vector type.  This is the default for AIDL.
+    //
+    // 4) Nullables
+    // std::optional, std::unique_ptr, std::shared_ptr are all parceled identically
+    // (i.e. result in identical byte layout).
+    // The target of the std::optional, std::unique_ptr, or std::shared_ptr
+    // can either be a std::vector, String16, std::string, or a Parcelable.
+    //
+    // Detection of null relies on peeking the first int32 data and checking if the
+    // the peeked value is considered invalid for the object:
+    // (-1 for vectors, String16, std::string) (0 for Parcelables).  If the peeked value
+    // is invalid, then a null is returned.
+    //
+    // Application Note: When to use each nullable type:
+    //
+    // std::optional: Embeds the object T by value rather than creating a new instance
+    // by managed pointer as std::unique_ptr or std::shared_ptr.  This will save a malloc
+    // when creating an optional instance.
+    //
+    // Use of std::optionals by value can result in copies of the underlying value stored in it,
+    // so a std::move may be used to move in and move out (for example) a vector value into
+    // the std::optional or for the std::optional itself.
+    //
+    // std::unique_ptr, std::shared_ptr: These are preferred when the lifetime of the object is
+    // already managed by the application.  This reduces unnecessary copying of data
+    // especially when the calls are local in-proc (rather than via binder rpc).
+    //
+    // 5) StrongBinder (sp<IBinder>)
+    // StrongBinder objects are written regardless of null. When read, null StrongBinder values
+    // will be interpreted as UNKNOWN_ERROR if the type is a single argument <sp<T>>
+    // or in a vector argument <std::vector<sp<T>>. However, they will be read without an error
+    // if present in a std::optional, std::unique_ptr, or std::shared_ptr vector, e.g.
+    // <std::optional<std::vector<sp<T>>>.
+    //
+    // See AIDL annotation @Nullable, readStrongBinder(), and readNullableStrongBinder().
+    //
+    // Historical Note: writing a vector of StrongBinder objects <std::vector<sp<T>>
+    // containing a null will not cause an error. However reading such a vector will cause
+    // an error _and_ early termination of the read.
 
-    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool> = 0>
-    status_t            readEnum(T* pArg) const;
-    template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool> = 0>
-    status_t            readEnum(T* pArg) const;
+    //  --- Examples
+    //
+    // Using recursive parceling, we can parcel complex data types so long
+    // as they obey the rules described above.
+    //
+    // Example #1
+    // Parceling of a 3D vector
+    //
+    // std::vector<std::vector<std::vector<int32_t>>> v1 {
+    //     { {1}, {2, 3}, {4} },
+    //     {},
+    //     { {10}, {20}, {30, 40} },
+    // };
+    // Parcel p1;
+    // p1.writeData(v1);
+    // decltype(v1) v2;
+    // p1.setDataPosition(0);
+    // p1.readData(&v2);
+    // ASSERT_EQ(v1, v2);
+    //
+    // Example #2
+    // Parceling of mixed shared pointers
+    //
+    // Parcel p1;
+    // auto sp1 = std::make_shared<std::vector<std::shared_ptr<std::vector<int>>>>(3);
+    // (*sp1)[2] = std::make_shared<std::vector<int>>(3);
+    // (*(*sp1)[2])[2] = 2;
+    // p1.writeData(sp1);
+    // decltype(sp1) sp2;
+    // p1.setDataPosition(0);
+    // p1.readData(&sp2);
+    // ASSERT_EQ((*sp1)[0], (*sp2)[0]); // nullptr
+    // ASSERT_EQ((*sp1)[1], (*sp2)[1]); // nullptr
+    // ASSERT_EQ(*(*sp1)[2], *(*sp2)[2]); // { 0, 0, 2}
 
-    status_t writeByteVectorInternal(const int8_t* data, size_t size);
-    template<typename T>
-    status_t readByteVectorInternal(std::vector<T>* val, size_t size) const;
+    //  --- Helper Methods
+    // TODO: move this to a utils header.
+    //
+    // Determine if a type is a specialization of a templated type
+    // Example: is_specialization_v<T, std::vector>
 
-    template<typename T, typename U>
-    status_t            unsafeReadTypedVector(std::vector<T>* val,
-                                              status_t(Parcel::*read_func)(U*) const) const;
-    template<typename T>
-    status_t            readNullableTypedVector(std::optional<std::vector<T>>* val,
-                                                status_t(Parcel::*read_func)(T*) const) const;
-    template<typename T>
-    status_t            readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
-                                                status_t(Parcel::*read_func)(T*) const) const __attribute__((deprecated("use std::optional version instead")));
-    template<typename T>
-    status_t            readTypedVector(std::vector<T>* val,
-                                        status_t(Parcel::*read_func)(T*) const) const;
-    template<typename T, typename U>
-    status_t            unsafeWriteTypedVector(const std::vector<T>& val,
-                                               status_t(Parcel::*write_func)(U));
-    template<typename T>
-    status_t            writeNullableTypedVector(const std::optional<std::vector<T>>& val,
-                                                 status_t(Parcel::*write_func)(const T&));
-    template<typename T>
-    status_t            writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
-                                                 status_t(Parcel::*write_func)(const T&)) __attribute__((deprecated("use std::optional version instead")));
-    template<typename T>
-    status_t            writeNullableTypedVector(const std::optional<std::vector<T>>& val,
-                                                 status_t(Parcel::*write_func)(T));
-    template<typename T>
-    status_t            writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
-                                                 status_t(Parcel::*write_func)(T)) __attribute__((deprecated("use std::optional version instead")));
-    template<typename T>
-    status_t            writeTypedVector(const std::vector<T>& val,
-                                         status_t(Parcel::*write_func)(const T&));
-    template<typename T>
-    status_t            writeTypedVector(const std::vector<T>& val,
-                                         status_t(Parcel::*write_func)(T));
+    template <typename Test, template <typename...> class Ref>
+    struct is_specialization : std::false_type {};
+
+    template <template <typename...> class Ref, typename... Args>
+    struct is_specialization<Ref<Args...>, Ref>: std::true_type {};
+
+    template <typename Test, template <typename...> class Ref>
+    static inline constexpr bool is_specialization_v = is_specialization<Test, Ref>::value;
+
+    // Get the first template type from a container, the T from MyClass<T, ...>.
+    template<typename T> struct first_template_type;
+
+    template <template <typename ...> class V, typename T, typename... Args>
+    struct first_template_type<V<T, Args...>> {
+        using type_t = T;
+    };
+
+    template <typename T>
+    using first_template_type_t = typename first_template_type<T>::type_t;
+
+    // For static assert(false) we need a template version to avoid early failure.
+    template <typename T>
+    static inline constexpr bool dependent_false_v = false;
+
+    // primitive types that we consider packed and trivially copyable as an array
+    template <typename T>
+    static inline constexpr bool is_pointer_equivalent_array_v =
+            std::is_same_v<T, int8_t>
+            || std::is_same_v<T, uint8_t>
+            // We could support int16_t and uint16_t, but those aren't currently AIDL types.
+            || std::is_same_v<T, int32_t>
+            || std::is_same_v<T, uint32_t>
+            || std::is_same_v<T, float>
+            // are unaligned reads and write support is assumed.
+            || std::is_same_v<T, uint64_t>
+            || std::is_same_v<T, int64_t>
+            || std::is_same_v<T, double>
+            || (std::is_enum_v<T> && (sizeof(T) == 1 || sizeof(T) == 4)); // size check not type
+
+    // allowed "nullable" types
+    // These are nonintrusive containers std::optional, std::unique_ptr, std::shared_ptr.
+    template <typename T>
+    static inline constexpr bool is_parcel_nullable_type_v =
+            is_specialization_v<T, std::optional>
+            || is_specialization_v<T, std::unique_ptr>
+            || is_specialization_v<T, std::shared_ptr>;
+
+    // special int32 value to indicate NonNull or Null parcelables
+    // This is fixed to be only 0 or 1 by contract, do not change.
+    static constexpr int32_t kNonNullParcelableFlag = 1;
+    static constexpr int32_t kNullParcelableFlag = 0;
+
+    // special int32 size representing a null vector, when applicable in Nullable data.
+    // This fixed as -1 by contract, do not change.
+    static constexpr int32_t kNullVectorSize = -1;
+
+    // --- readData and writeData methods.
+    // We choose a mixture of function and template overloads to improve code readability.
+    // TODO: Consider C++20 concepts when they become available.
+
+    // writeData function overloads.
+    // Implementation detail: Function overloading improves code readability over
+    // template overloading, but prevents writeData<T> from being used for those types.
+
+    status_t writeData(bool t) {
+        return writeBool(t);  // this writes as int32_t
+    }
+
+    status_t writeData(int8_t t) {
+        return writeByte(t);  // this writes as int32_t
+    }
+
+    status_t writeData(uint8_t t) {
+        return writeByte(static_cast<int8_t>(t));  // this writes as int32_t
+    }
+
+    status_t writeData(char16_t t) {
+        return writeChar(t);  // this writes as int32_t
+    }
+
+    status_t writeData(int32_t t) {
+        return writeInt32(t);
+    }
+
+    status_t writeData(uint32_t t) {
+        return writeUint32(t);
+    }
+
+    status_t writeData(int64_t t) {
+        return writeInt64(t);
+    }
+
+    status_t writeData(uint64_t t) {
+        return writeUint64(t);
+    }
+
+    status_t writeData(float t) {
+        return writeFloat(t);
+    }
+
+    status_t writeData(double t) {
+        return writeDouble(t);
+    }
+
+    status_t writeData(const String16& t) {
+        return writeString16(t);
+    }
+
+    status_t writeData(const std::string& t) {
+        return writeUtf8AsUtf16(t);
+    }
+
+    status_t writeData(const base::unique_fd& t) {
+        return writeUniqueFileDescriptor(t);
+    }
+
+    status_t writeData(const Parcelable& t) {  // std::is_base_of_v<Parcelable, T>
+        // implemented here. writeParcelable() calls this.
+        status_t status = writeData(static_cast<int32_t>(kNonNullParcelableFlag));
+        if (status != OK) return status;
+        return t.writeToParcel(this);
+    }
+
+    // writeData<T> template overloads.
+    // Written such that the first template type parameter is the complete type
+    // of the first function parameter.
+    template <typename T,
+            typename std::enable_if_t<std::is_enum_v<T>, bool> = true>
+    status_t writeData(const T& t) {
+        // implemented here. writeEnum() calls this.
+        using UT = std::underlying_type_t<T>;
+        return writeData(static_cast<UT>(t)); // recurse
+    }
+
+    template <typename T,
+            typename std::enable_if_t<is_specialization_v<T, sp>, bool> = true>
+    status_t writeData(const T& t) {
+        return writeStrongBinder(t);
+    }
+
+    // std::optional, std::unique_ptr, std::shared_ptr special case.
+    template <typename CT,
+            typename std::enable_if_t<is_parcel_nullable_type_v<CT>, bool> = true>
+    status_t writeData(const CT& c) {
+        using T = first_template_type_t<CT>;  // The T in CT == C<T, ...>
+        if constexpr (is_specialization_v<T, std::vector>
+                || std::is_same_v<T, String16>
+                || std::is_same_v<T, std::string>) {
+            if (!c) return writeData(static_cast<int32_t>(kNullVectorSize));
+        } else if constexpr (std::is_base_of_v<Parcelable, T>) {
+            if (!c) return writeData(static_cast<int32_t>(kNullParcelableFlag));
+        } else /* constexpr */ {  // could define this, but raise as error.
+            static_assert(dependent_false_v<CT>);
+        }
+        return writeData(*c);
+    }
+
+    template <typename CT,
+            typename std::enable_if_t<is_specialization_v<CT, std::vector>, bool> = true>
+    status_t writeData(const CT& c) {
+        using T = first_template_type_t<CT>;  // The T in CT == C<T, ...>
+        if (c.size() >  std::numeric_limits<int32_t>::max()) return BAD_VALUE;
+        const auto size = static_cast<int32_t>(c.size());
+        writeData(size);
+        if constexpr (is_pointer_equivalent_array_v<T>) {
+            constexpr size_t limit = std::numeric_limits<size_t>::max() / sizeof(T);
+            if (c.size() > limit) return BAD_VALUE;
+            // is_pointer_equivalent types do not have gaps which could leak info,
+            // which is only a concern when writing through binder.
+
+            // TODO: Padding of the write is suboptimal when the length of the
+            // data is not a multiple of 4.  Consider improving the write() method.
+            return write(c.data(), c.size() * sizeof(T));
+        } else if constexpr (std::is_same_v<T, bool>
+                || std::is_same_v<T, char16_t>) {
+            // reserve data space to write to
+            auto data = reinterpret_cast<int32_t*>(writeInplace(c.size() * sizeof(int32_t)));
+            if (data == nullptr) return BAD_VALUE;
+            for (const auto t: c) {
+                *data++ = static_cast<int32_t>(t);
+            }
+        } else /* constexpr */ {
+            for (const auto &t : c) {
+                const status_t status = writeData(t);
+                if (status != OK) return status;
+            }
+        }
+        return OK;
+    }
+
+    // readData function overloads.
+    // Implementation detail: Function overloading improves code readability over
+    // template overloading, but prevents readData<T> from being used for those types.
+
+    status_t readData(bool* t) const {
+        return readBool(t);  // this reads as int32_t
+    }
+
+    status_t readData(int8_t* t) const {
+        return readByte(t);  // this reads as int32_t
+    }
+
+    status_t readData(uint8_t* t) const {
+        return readByte(reinterpret_cast<int8_t*>(t));  // NOTE: this reads as int32_t
+    }
+
+    status_t readData(char16_t* t) const {
+        return readChar(t);  // this reads as int32_t
+    }
+
+    status_t readData(int32_t* t) const {
+        return readInt32(t);
+    }
+
+    status_t readData(uint32_t* t) const {
+        return readUint32(t);
+    }
+
+    status_t readData(int64_t* t) const {
+        return readInt64(t);
+    }
+
+    status_t readData(uint64_t* t) const {
+        return readUint64(t);
+    }
+
+    status_t readData(float* t) const {
+        return readFloat(t);
+    }
+
+    status_t readData(double* t) const {
+        return readDouble(t);
+    }
+
+    status_t readData(String16* t) const {
+        return readString16(t);
+    }
+
+    status_t readData(std::string* t) const {
+        return readUtf8FromUtf16(t);
+    }
+
+    status_t readData(base::unique_fd* t) const {
+        return readUniqueFileDescriptor(t);
+    }
+
+    status_t readData(Parcelable* t) const { // std::is_base_of_v<Parcelable, T>
+        // implemented here. readParcelable() calls this.
+        int32_t present;
+        status_t status = readData(&present);
+        if (status != OK) return status;
+        if (present != kNonNullParcelableFlag) return UNEXPECTED_NULL;
+        return t->readFromParcel(this);
+    }
+
+    // readData<T> template overloads.
+    // Written such that the first template type parameter is the complete type
+    // of the first function parameter.
+
+    template <typename T,
+            typename std::enable_if_t<std::is_enum_v<T>, bool> = true>
+    status_t readData(T* t) const {
+        // implemented here. readEnum() calls this.
+        using UT = std::underlying_type_t<T>;
+        return readData(reinterpret_cast<UT*>(t));
+    }
+
+    template <typename T,
+            typename std::enable_if_t<is_specialization_v<T, sp>, bool> = true>
+    status_t readData(T* t) const {
+        return readStrongBinder(t);  // Note: on null, returns failure
+    }
+
+
+    template <typename CT,
+            typename std::enable_if_t<is_parcel_nullable_type_v<CT>, bool> = true>
+    status_t readData(CT* c) const {
+        using T = first_template_type_t<CT>;  // The T in CT == C<T, ...>
+        const size_t startPos = dataPosition();
+        int32_t peek;
+        status_t status = readData(&peek);
+        if (status != OK) return status;
+        if constexpr (is_specialization_v<T, std::vector>
+                || std::is_same_v<T, String16>
+                || std::is_same_v<T, std::string>) {
+            if (peek == kNullVectorSize) {
+                c->reset();
+                return OK;
+            }
+        } else if constexpr (std::is_base_of_v<Parcelable, T>) {
+            if (peek == kNullParcelableFlag) {
+                c->reset();
+                return OK;
+            }
+        } else /* constexpr */ {  // could define this, but raise as error.
+            static_assert(dependent_false_v<CT>);
+        }
+        // create a new object.
+        if constexpr (is_specialization_v<CT, std::optional>) {
+            c->emplace();
+        } else /* constexpr */ {
+            T* const t = new (std::nothrow) T;  // contents read from Parcel below.
+            if (t == nullptr) return NO_MEMORY;
+            c->reset(t);
+        }
+        // rewind data ptr to reread (this is pretty quick), otherwise we could
+        // pass an optional argument to readData to indicate a peeked value.
+        setDataPosition(startPos);
+        if constexpr (is_specialization_v<T, std::vector>) {
+            return readData(&**c, READ_FLAG_SP_NULLABLE);  // nullable sp<> allowed now
+        } else {
+            return readData(&**c);
+        }
+    }
+
+    // std::vector special case, incorporating flags whether the vector
+    // accepts nullable sp<> to be read.
+    enum ReadFlags {
+        READ_FLAG_NONE = 0,
+        READ_FLAG_SP_NULLABLE = 1 << 0,
+    };
+
+    template <typename CT,
+            typename std::enable_if_t<is_specialization_v<CT, std::vector>, bool> = true>
+    status_t readData(CT* c, ReadFlags readFlags = READ_FLAG_NONE) const {
+        using T = first_template_type_t<CT>;  // The T in CT == C<T, ...>
+        int32_t size;
+        status_t status = readInt32(&size);
+        if (status != OK) return status;
+        if (size < 0) return UNEXPECTED_NULL;
+        const size_t availableBytes = dataAvail();  // coarse bound on vector size.
+        if (static_cast<size_t>(size) > availableBytes) return BAD_VALUE;
+        c->clear(); // must clear before resizing/reserving otherwise move ctors may be called.
+        if constexpr (is_pointer_equivalent_array_v<T>) {
+            // could consider POD without gaps and alignment of 4.
+            auto data = reinterpret_cast<const T*>(
+                    readInplace(static_cast<size_t>(size) * sizeof(T)));
+            if (data == nullptr) return BAD_VALUE;
+            c->insert(c->begin(), data, data + size); // insert should do a reserve().
+        } else if constexpr (std::is_same_v<T, bool>
+                || std::is_same_v<T, char16_t>) {
+            c->reserve(size); // avoids default initialization
+            auto data = reinterpret_cast<const int32_t*>(
+                    readInplace(static_cast<size_t>(size) * sizeof(int32_t)));
+            if (data == nullptr) return BAD_VALUE;
+            for (int32_t i = 0; i < size; ++i) {
+                c->emplace_back(static_cast<T>(*data++));
+            }
+        } else if constexpr (is_specialization_v<T, sp>) {
+            c->resize(size); // calls ctor
+            if (readFlags & READ_FLAG_SP_NULLABLE) {
+                for (auto &t : *c) {
+                    status = readNullableStrongBinder(&t);  // allow nullable
+                    if (status != OK) return status;
+                }
+            } else {
+                for (auto &t : *c) {
+                    status = readStrongBinder(&t);
+                    if (status != OK) return status;
+                }
+            }
+        } else /* constexpr */ {
+            c->resize(size); // calls ctor
+            for (auto &t : *c) {
+                status = readData(&t);
+                if (status != OK) return status;
+            }
+        }
+        return OK;
+    }
+
+    //-----------------------------------------------------------------------------
+    private:
 
     status_t            mError;
     uint8_t*            mData;
@@ -792,7 +1298,6 @@
 template<typename T>
 status_t Parcel::resizeOutVector(std::vector<T>* val) const {
     int32_t size;
-    // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
     status_t err = readInt32(&size);
     if (err != NO_ERROR) {
         return err;
@@ -808,7 +1313,6 @@
 template<typename T>
 status_t Parcel::resizeOutVector(std::optional<std::vector<T>>* val) const {
     int32_t size;
-    // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
     status_t err = readInt32(&size);
     if (err != NO_ERROR) {
         return err;
@@ -825,7 +1329,6 @@
 template<typename T>
 status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const {
     int32_t size;
-    // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
     status_t err = readInt32(&size);
     if (err != NO_ERROR) {
         return err;
@@ -840,61 +1343,6 @@
 }
 
 template<typename T>
-status_t Parcel::reserveOutVector(std::vector<T>* val, size_t* size) const {
-    int32_t read_size;
-    status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    if (read_size < 0) {
-        return UNEXPECTED_NULL;
-    }
-    *size = static_cast<size_t>(read_size);
-    val->reserve(*size);
-    return OK;
-}
-
-template<typename T>
-status_t Parcel::reserveOutVector(std::optional<std::vector<T>>* val, size_t* size) const {
-    int32_t read_size;
-    status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    if (read_size >= 0) {
-        *size = static_cast<size_t>(read_size);
-        val->emplace();
-        (*val)->reserve(*size);
-    } else {
-        val->reset();
-    }
-
-    return OK;
-}
-
-template<typename T>
-status_t Parcel::reserveOutVector(std::unique_ptr<std::vector<T>>* val,
-                                  size_t* size) const {
-    int32_t read_size;
-    status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    if (read_size >= 0) {
-        *size = static_cast<size_t>(read_size);
-        val->reset(new std::vector<T>());
-        (*val)->reserve(*size);
-    } else {
-        val->reset();
-    }
-
-    return OK;
-}
-
-template<typename T>
 status_t Parcel::readStrongBinder(sp<T>* val) const {
     sp<IBinder> tmp;
     status_t ret = readStrongBinder(&tmp);
@@ -926,422 +1374,6 @@
     return ret;
 }
 
-template<typename T, typename U>
-status_t Parcel::unsafeReadTypedVector(
-        std::vector<T>* val,
-        status_t(Parcel::*read_func)(U*) const) const {
-    int32_t size;
-    status_t status = this->readVectorSizeWithCoarseBoundCheck(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        return UNEXPECTED_NULL;
-    }
-
-    if (val->max_size() < static_cast<size_t>(size)) {
-        return NO_MEMORY;
-    }
-
-    val->resize(static_cast<size_t>(size));
-
-    if (val->size() < static_cast<size_t>(size)) {
-        return NO_MEMORY;
-    }
-
-    for (auto& v: *val) {
-        status = (this->*read_func)(&v);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
-}
-
-template<typename T>
-status_t Parcel::readTypedVector(std::vector<T>* val,
-                                 status_t(Parcel::*read_func)(T*) const) const {
-    return unsafeReadTypedVector(val, read_func);
-}
-
-template<typename T>
-status_t Parcel::readNullableTypedVector(std::optional<std::vector<T>>* val,
-                                         status_t(Parcel::*read_func)(T*) const) const {
-    const size_t start = dataPosition();
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->emplace();
-
-    status = unsafeReadTypedVector(&**val, read_func);
-
-    if (status != OK) {
-       val->reset();
-    }
-
-    return status;
-}
-
-template<typename T>
-status_t Parcel::readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
-                                         status_t(Parcel::*read_func)(T*) const) const {
-    const size_t start = dataPosition();
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->reset(new std::vector<T>());
-
-    status = unsafeReadTypedVector(val->get(), read_func);
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-template<typename T, typename U>
-status_t Parcel::unsafeWriteTypedVector(const std::vector<T>& val,
-                                        status_t(Parcel::*write_func)(U)) {
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
-
-    status_t status = this->writeInt32(static_cast<int32_t>(val.size()));
-
-    if (status != OK) {
-        return status;
-    }
-
-    for (const auto& item : val) {
-        status = (this->*write_func)(item);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
-}
-
-template<typename T>
-status_t Parcel::writeTypedVector(const std::vector<T>& val,
-                                  status_t(Parcel::*write_func)(const T&)) {
-    return unsafeWriteTypedVector(val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeTypedVector(const std::vector<T>& val,
-                                  status_t(Parcel::*write_func)(T)) {
-    return unsafeWriteTypedVector(val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::optional<std::vector<T>>& val,
-                                          status_t(Parcel::*write_func)(const T&)) {
-    if (!val) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
-                                          status_t(Parcel::*write_func)(const T&)) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::optional<std::vector<T>>& val,
-                                          status_t(Parcel::*write_func)(T)) {
-    if (!val) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
-                                          status_t(Parcel::*write_func)(T)) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, write_func);
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::vector<T>* val) const {
-    return unsafeReadTypedVector<T, Parcelable>(val, &Parcel::readParcelable);
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::optional<std::vector<std::optional<T>>>* val) const {
-    const size_t start = dataPosition();
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->emplace();
-
-    using NullableT = std::optional<T>;
-    status = unsafeReadTypedVector<NullableT, NullableT>(&**val, &Parcel::readParcelable);
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelableVector(std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const {
-    const size_t start = dataPosition();
-    int32_t size;
-    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
-    val->reset();
-
-    if (status != OK || size < 0) {
-        return status;
-    }
-
-    setDataPosition(start);
-    val->reset(new std::vector<std::unique_ptr<T>>());
-
-    using NullableT = std::unique_ptr<T>;
-    status = unsafeReadTypedVector<NullableT, NullableT>(val->get(), &Parcel::readParcelable);
-
-    if (status != OK) {
-        val->reset();
-    }
-
-    return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelable(std::optional<T>* parcelable) const {
-    const size_t start = dataPosition();
-    int32_t present;
-    status_t status = readInt32(&present);
-    parcelable->reset();
-
-    if (status != OK || !present) {
-        return status;
-    }
-
-    setDataPosition(start);
-    parcelable->emplace();
-
-    status = readParcelable(&**parcelable);
-
-    if (status != OK) {
-        parcelable->reset();
-    }
-
-    return status;
-}
-
-template<typename T>
-status_t Parcel::readParcelable(std::unique_ptr<T>* parcelable) const {
-    const size_t start = dataPosition();
-    int32_t present;
-    status_t status = readInt32(&present);
-    parcelable->reset();
-
-    if (status != OK || !present) {
-        return status;
-    }
-
-    setDataPosition(start);
-    parcelable->reset(new T());
-
-    status = readParcelable(parcelable->get());
-
-    if (status != OK) {
-        parcelable->reset();
-    }
-
-    return status;
-}
-
-template<typename T>
-status_t Parcel::writeNullableParcelable(const std::optional<T>& parcelable) {
-    return writeRawNullableParcelable(parcelable ? &*parcelable : nullptr);
-}
-
-template<typename T>
-status_t Parcel::writeNullableParcelable(const std::unique_ptr<T>& parcelable) {
-    return writeRawNullableParcelable(parcelable.get());
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::vector<T>& val) {
-    return unsafeWriteTypedVector<T,const Parcelable&>(val, &Parcel::writeParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val) {
-    if (!val) {
-        return this->writeInt32(-1);
-    }
-
-    using NullableT = std::optional<T>;
-    return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable<T>);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    using NullableT = std::unique_ptr<T>;
-    return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
-}
-
-template<typename T>
-status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val) {
-    if (val.get() == nullptr) {
-        return this->writeInt32(-1);
-    }
-
-    using NullableT = std::optional<T>;
-    return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
-}
-
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
-status_t Parcel::writeEnum(const T& val) {
-    return writeInt32(static_cast<int32_t>(val));
-}
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>>
-status_t Parcel::writeEnum(const T& val) {
-    return writeInt64(static_cast<int64_t>(val));
-}
-
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::vector<T>& val) {
-    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::optional<std::vector<T>>& val) {
-    if (!val) return writeInt32(-1);
-    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
-    if (!val) return writeInt32(-1);
-    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::vector<T>& val) {
-    return writeTypedVector(val, &Parcel::writeEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::optional<std::vector<T>>& val) {
-    return writeNullableTypedVector(val, &Parcel::writeEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
-    return writeNullableTypedVector(val, &Parcel::writeEnum);
-}
-
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
-status_t Parcel::readEnum(T* pArg) const {
-    return readInt32(reinterpret_cast<int32_t *>(pArg));
-}
-template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int64_t>, bool>>
-status_t Parcel::readEnum(T* pArg) const {
-    return readInt64(reinterpret_cast<int64_t *>(pArg));
-}
-
-template<typename T>
-inline status_t Parcel::readByteVectorInternal(std::vector<T>* val, size_t size) const {
-  // readByteVectorInternal expects a vector that has been reserved (but not
-  // resized) to have the provided size.
-  const T* data = reinterpret_cast<const T*>(readInplace(size));
-  if (!data) return BAD_VALUE;
-  val->clear();
-  val->insert(val->begin(), data, data+size);
-  return NO_ERROR;
-}
-
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::vector<T>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    return readByteVectorInternal(val, size);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::optional<std::vector<T>>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    if (!*val) {
-        // reserveOutVector does not create the out vector if size is < 0.
-        // This occurs when writing a null Enum vector.
-        return OK;
-    }
-    return readByteVectorInternal(&**val, size);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
-    size_t size;
-    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
-    if (val->get() == nullptr) {
-        // reserveOutVector does not create the out vector if size is < 0.
-        // This occurs when writing a null Enum vector.
-        return OK;
-    }
-    return readByteVectorInternal(val->get(), size);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::vector<T>* val) const {
-    return readTypedVector(val, &Parcel::readEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::optional<std::vector<T>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readEnum);
-}
-template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
-status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
-    return readNullableTypedVector(val, &Parcel::readEnum);
-}
-
 // ---------------------------------------------------------------------------
 
 inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
diff --git a/libs/binder/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h
index 5a719b8..1579199 100644
--- a/libs/binder/include/private/binder/binder_module.h
+++ b/libs/binder/include/private/binder/binder_module.h
@@ -88,10 +88,6 @@
 };
 #endif //BINDER_GET_FROZEN_INFO
 
-enum transaction_flags_ext {
-    TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */
-};
-
 #ifdef __cplusplus
 }   // namespace android
 #endif
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 897c72a..eb103d3 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -15,6 +15,23 @@
  */
 
 // TODO(b/31559095): bionic on host should define this
+package {
+    default_applicable_licenses: ["frameworks_native_libs_binder_ndk_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_libs_binder_ndk_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_defaults {
     name: "libbinder_ndk_host_user",
     target: {
diff --git a/libs/binder/ndk/include_cpp/android/binder_to_string.h b/libs/binder/ndk/include_cpp/android/binder_to_string.h
index bd51b11..5842925 100644
--- a/libs/binder/ndk/include_cpp/android/binder_to_string.h
+++ b/libs/binder/ndk/include_cpp/android/binder_to_string.h
@@ -28,10 +28,22 @@
 
 #include <codecvt>
 #include <locale>
+#include <memory>
+#include <optional>
 #include <sstream>
 #include <string>
 #include <type_traits>
 
+#if __has_include(<utils/StrongPointer.h>)
+#include <utils/StrongPointer.h>
+#define HAS_STRONG_POINTER
+#endif
+
+#if __has_include(<utils/String16.h>)
+#include <utils/String16.h>
+#define HAS_STRING16
+#endif
+
 #if __has_include(<android/binder_ibinder.h>)
 #include <android/binder_auto_utils.h>
 #include <android/binder_interface_utils.h>
@@ -42,9 +54,6 @@
 #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 {
@@ -80,11 +89,28 @@
     enum { value = decltype(_test<_T>(0))::value };
 };
 
-// Truthy if _T is like a pointer
+template <typename T, template <typename...> typename U>
+struct IsInstantiationOf : std::false_type {};
+
+template <template <typename...> typename U, typename... Args>
+struct IsInstantiationOf<U<Args...>, U> : std::true_type {};
+
+// Truthy if _T is like a pointer: one of sp/optional/shared_ptr
 template <typename _T>
 class IsPointerLike {
     template <typename _U>
-    static auto _test(int) -> decltype(!std::declval<_U>(), *std::declval<_U>(), std::true_type());
+    static std::enable_if_t<
+#ifdef HAS_STRONG_POINTER
+            IsInstantiationOf<_U, sp>::value ||  // for IBinder and interface types in the C++
+                                                 // backend
+#endif
+                    IsInstantiationOf<_U, std::optional>::value ||  // for @nullable types in the
+                                                                    // C++/NDK backends
+                    IsInstantiationOf<_U, std::shared_ptr>::value,  // for interface types in the
+                                                                    // NDK backends
+
+            std::true_type>
+    _test(int);
     template <typename _U>
     static std::false_type _test(...);
 
@@ -142,12 +168,17 @@
         return std::to_string(t);
     } else if constexpr (std::is_same_v<std::string, _T>) {
         return t;
-#ifdef HAS_CPP_INTERFACE
+#ifdef HAS_STRING16
     } else if constexpr (std::is_same_v<String16, _T>) {
         std::stringstream out;
         out << t;
         return out.str();
 #endif
+    } else if constexpr (details::IsPointerLike<_T>::value) {
+        if (!t) return "(null)";
+        std::stringstream out;
+        out << ToString(*t);
+        return out.str();
     } else if constexpr (details::HasToStringMethod<_T>::value) {
         return t.toString();
     } else if constexpr (details::HasToStringFunction<_T>::value) {
@@ -168,11 +199,6 @@
         }
         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}";
     }
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 2784aa8..4580751 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -31,7 +31,8 @@
  *
  * \return EX_NONE on success.
  */
-binder_exception_t AServiceManager_addService(AIBinder* binder, const char* instance);
+__attribute__((warn_unused_result)) binder_exception_t AServiceManager_addService(
+        AIBinder* binder, const char* instance);
 
 /**
  * Gets a binder object with this specific instance name. Will return nullptr immediately if the
@@ -94,4 +95,52 @@
  */
 bool AServiceManager_isDeclared(const char* instance) __INTRODUCED_IN(31);
 
+/**
+ * Prevent lazy services without client from shutting down their process
+ *
+ * \param persist 'true' if the process should not exit.
+ */
+void AServiceManager_forceLazyServicesPersist(bool persist) __INTRODUCED_IN(31);
+
+/**
+ * Set a callback that is invoked when the active service count (i.e. services with clients)
+ * registered with this process drops to zero (or becomes nonzero).
+ * The callback takes a boolean argument, which is 'true' if there is
+ * at least one service with clients.
+ *
+ * \param callback function to call when the number of services
+ *    with clients changes.
+ * \param context opaque pointer passed back as second parameter to the
+ * callback.
+ *
+ * The callback takes two arguments. The first is a boolean that represents if there are
+ * services with clients (true) or not (false).
+ * The second is the 'context' pointer passed during the registration.
+ *
+ * Callback return value:
+ * - false: Default behavior for lazy services (shut down the process if there
+ *          are no clients).
+ * - true:  Don't shut down the process even if there are no clients.
+ *
+ * This callback gives a chance to:
+ * 1 - Perform some additional operations before exiting;
+ * 2 - Prevent the process from exiting by returning "true" from the callback.
+ */
+void AServiceManager_setActiveServicesCallback(bool (*callback)(bool, void*), void* context)
+        __INTRODUCED_IN(31);
+
+/**
+ * Try to unregister all services previously registered with 'registerService'.
+ *
+ * \return true on success.
+ */
+bool AServiceManager_tryUnregister() __INTRODUCED_IN(31);
+
+/**
+ * Re-register services that were unregistered by 'tryUnregister'.
+ * This method should be called in the case 'tryUnregister' fails
+ * (and should be called on the same thread).
+ */
+void AServiceManager_reRegister() __INTRODUCED_IN(31);
+
 __END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index f5e8bf6..44ed48f 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -30,6 +30,8 @@
     FLAG_PRIVATE_VENDOR = 0x10000000,
 };
 
+// TODO(b/180646847): __ANDROID_APEX__ here is what allows product partition to
+// talk to system.
 #if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
 
 enum {
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 9a93bf3..cef0bf3 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -120,6 +120,10 @@
     AServiceManager_isDeclared; # apex llndk
     AServiceManager_registerLazyService; # llndk
     AServiceManager_waitForService; # apex llndk
+    AServiceManager_forceLazyServicesPersist; # llndk
+    AServiceManager_setActiveServicesCallback; # llndk
+    AServiceManager_tryUnregister; # llndk
+    AServiceManager_reRegister; # llndk
 
     AIBinder_Class_getDescriptor;
     AIBinder_Weak_clone;
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index c782d47..cb0987e 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -92,3 +92,22 @@
     sp<IServiceManager> sm = defaultServiceManager();
     return sm->isDeclared(String16(instance));
 }
+void AServiceManager_forceLazyServicesPersist(bool persist) {
+    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+    serviceRegistrar.forcePersist(persist);
+}
+void AServiceManager_setActiveServicesCallback(bool (*callback)(bool, void*), void* context) {
+    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+    std::function<bool(bool)> fn = [=](bool hasClients) -> bool {
+        return callback(hasClients, context);
+    };
+    serviceRegistrar.setActiveServicesCallback(fn);
+}
+bool AServiceManager_tryUnregister() {
+    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+    return serviceRegistrar.tryUnregister();
+}
+void AServiceManager_reRegister() {
+    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+    serviceRegistrar.reRegister();
+}
\ No newline at end of file
diff --git a/libs/binder/ndk/tests/Android.bp b/libs/binder/ndk/tests/Android.bp
index 46e6270..bb51bf0 100644
--- a/libs/binder/ndk/tests/Android.bp
+++ b/libs/binder/ndk/tests/Android.bp
@@ -14,6 +14,15 @@
  * limitations under the License.
  */
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_libs_binder_ndk_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_libs_binder_ndk_license"],
+}
+
 cc_defaults {
     name: "test_libbinder_ndk_defaults",
     shared_libs: [
diff --git a/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
index dc77467d..ecbd649 100644
--- a/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
+++ b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
@@ -28,4 +28,7 @@
     void forceFlushCommands();
 
     boolean getsRequestedSid();
+
+    void forcePersist(boolean persist);
+    void setCustomActiveServicesCallback();
 }
diff --git a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
index ad78e31..f3cd218 100644
--- a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
+++ b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
@@ -163,7 +163,8 @@
 
     // LOCAL SERVERS
     std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>();
-    AServiceManager_addService(ndkServer->asBinder().get(), kLocalNdkServerName.c_str());
+    CHECK(STATUS_OK ==
+          AServiceManager_addService(ndkServer->asBinder().get(), kLocalNdkServerName.c_str()));
 
     return RUN_ALL_TESTS();
 }
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 0d1989e..de1a48d 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -46,6 +46,11 @@
 constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
 constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
 constexpr char kLazyBinderNdkUnitTestService[] = "LazyBinderNdkUnitTest";
+constexpr char kForcePersistNdkUnitTestService[] = "ForcePersistNdkUnitTestService";
+constexpr char kActiveServicesNdkUnitTestService[] = "ActiveServicesNdkUnitTestService";
+
+constexpr unsigned int kShutdownWaitTime = 10;
+constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715;
 
 class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
     ndk::ScopedAStatus repeatInt(int32_t in, int32_t* out) {
@@ -76,6 +81,46 @@
         fsync(out);
         return STATUS_OK;
     }
+    ndk::ScopedAStatus forcePersist(bool persist) {
+        AServiceManager_forceLazyServicesPersist(persist);
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus setCustomActiveServicesCallback() {
+        AServiceManager_setActiveServicesCallback(activeServicesCallback, this);
+        return ndk::ScopedAStatus::ok();
+    }
+    static bool activeServicesCallback(bool hasClients, void* context) {
+        if (hasClients) {
+            return false;
+        }
+
+        // Unregister all services
+        if (!AServiceManager_tryUnregister()) {
+            // Prevent shutdown (test will fail)
+            return false;
+        }
+
+        // Re-register all services
+        AServiceManager_reRegister();
+
+        // Unregister again before shutdown
+        if (!AServiceManager_tryUnregister()) {
+            // Prevent shutdown (test will fail)
+            return false;
+        }
+
+        // Check if the context was passed correctly
+        MyBinderNdkUnitTest* service = static_cast<MyBinderNdkUnitTest*>(context);
+        if (service->contextTestValue != kContextTestValue) {
+            // Prevent shutdown (test will fail)
+            return false;
+        }
+
+        exit(EXIT_SUCCESS);
+        // Unreachable
+    }
+
+    uint64_t contextTestValue = kContextTestValue;
 };
 
 int generatedService() {
@@ -168,6 +213,16 @@
     return 1;  // should not return
 }
 
+bool isServiceRunning(const char* serviceName) {
+    AIBinder* binder = AServiceManager_checkService(serviceName);
+    if (binder == nullptr) {
+        return false;
+    }
+    AIBinder_decStrong(binder);
+
+    return true;
+}
+
 TEST(NdkBinder, GetServiceThatDoesntExist) {
     sp<IFoo> foo = IFoo::getService("asdfghkl;");
     EXPECT_EQ(nullptr, foo.get());
@@ -238,10 +293,51 @@
     service = nullptr;
     IPCThreadState::self()->flushCommands();
     // Make sure the service is dead after some time of no use
-    sleep(10);
+    sleep(kShutdownWaitTime);
     ASSERT_EQ(nullptr, AServiceManager_checkService(kLazyBinderNdkUnitTestService));
 }
 
+TEST(NdkBinder, ForcedPersistenceTest) {
+    for (int i = 0; i < 2; i++) {
+        ndk::SpAIBinder binder(AServiceManager_waitForService(kForcePersistNdkUnitTestService));
+        std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+                aidl::IBinderNdkUnitTest::fromBinder(binder);
+        ASSERT_NE(service, nullptr);
+        ASSERT_TRUE(service->forcePersist(i == 0).isOk());
+
+        binder = nullptr;
+        service = nullptr;
+        IPCThreadState::self()->flushCommands();
+
+        sleep(kShutdownWaitTime);
+
+        bool isRunning = isServiceRunning(kForcePersistNdkUnitTestService);
+
+        if (i == 0) {
+            ASSERT_TRUE(isRunning) << "Service shut down when it shouldn't have.";
+        } else {
+            ASSERT_FALSE(isRunning) << "Service failed to shut down.";
+        }
+    }
+}
+
+TEST(NdkBinder, ActiveServicesCallbackTest) {
+    ndk::SpAIBinder binder(AServiceManager_waitForService(kActiveServicesNdkUnitTestService));
+    std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+            aidl::IBinderNdkUnitTest::fromBinder(binder);
+    ASSERT_NE(service, nullptr);
+    ASSERT_TRUE(service->setCustomActiveServicesCallback().isOk());
+
+    binder = nullptr;
+    service = nullptr;
+    IPCThreadState::self()->flushCommands();
+
+    sleep(kShutdownWaitTime);
+
+    ASSERT_FALSE(isServiceRunning(kActiveServicesNdkUnitTestService))
+            << "Service failed to shut down.";
+}
+
 void LambdaOnDeath(void* cookie) {
     auto onDeath = static_cast<std::function<void(void)>*>(cookie);
     (*onDeath)();
@@ -564,10 +660,18 @@
     }
     if (fork() == 0) {
         prctl(PR_SET_PDEATHSIG, SIGHUP);
+        return lazyService(kForcePersistNdkUnitTestService);
+    }
+    if (fork() == 0) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+        return lazyService(kActiveServicesNdkUnitTestService);
+    }
+    if (fork() == 0) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
         return generatedService();
     }
 
-    ABinderProcess_setThreadPoolMaxThreadCount(1);  // to recieve death notifications/callbacks
+    ABinderProcess_setThreadPoolMaxThreadCount(1);  // to receive death notifications/callbacks
     ABinderProcess_startThreadPool();
 
     return RUN_ALL_TESTS();
diff --git a/libs/binder/parcel_fuzzer/Android.bp b/libs/binder/parcel_fuzzer/Android.bp
index 3e6fe99..74b8eb8 100644
--- a/libs/binder/parcel_fuzzer/Android.bp
+++ b/libs/binder/parcel_fuzzer/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_fuzz {
     name: "binder_parcel_fuzzer",
     defaults: ["libbinder_ndk_host_user"],
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index fd5f2f5..e12a429 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 rust_library {
     name: "libbinder_rs",
     crate_name: "binder",
@@ -14,7 +23,11 @@
         darwin: {
             enabled: false,
         }
-    }
+    },
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
+    ],
 }
 
 rust_library {
@@ -32,7 +45,11 @@
         darwin: {
             enabled: false,
         }
-    }
+    },
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
+    ],
 }
 
 rust_bindgen {
@@ -78,6 +95,10 @@
             enabled: false,
         },
     },
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
+    ],
 }
 
 rust_test {
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 42c1e0a..d53a88f 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -16,12 +16,17 @@
 
 //! Trait definitions for binder objects
 
-use crate::error::{status_t, Result};
+use crate::error::{status_t, Result, StatusCode};
 use crate::parcel::Parcel;
-use crate::proxy::{DeathRecipient, SpIBinder};
+use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
 use crate::sys;
 
+use std::borrow::Borrow;
+use std::cmp::Ordering;
 use std::ffi::{c_void, CStr, CString};
+use std::fmt;
+use std::marker::PhantomData;
+use std::ops::Deref;
 use std::os::raw::c_char;
 use std::os::unix::io::AsRawFd;
 use std::ptr;
@@ -44,7 +49,7 @@
 /// interfaces) must implement this trait.
 ///
 /// This is equivalent `IInterface` in C++.
-pub trait Interface {
+pub trait Interface: Send {
     /// Convert this binder object into a generic [`SpIBinder`] reference.
     fn as_binder(&self) -> SpIBinder {
         panic!("This object was not a Binder object and cannot be converted into an SpIBinder.")
@@ -230,6 +235,132 @@
     }
 }
 
+/// Strong reference to a binder object
+pub struct Strong<I: FromIBinder + ?Sized>(Box<I>);
+
+impl<I: FromIBinder + ?Sized> Strong<I> {
+    /// Create a new strong reference to the provided binder object
+    pub fn new(binder: Box<I>) -> Self {
+        Self(binder)
+    }
+
+    /// Construct a new weak reference to this binder
+    pub fn downgrade(this: &Strong<I>) -> Weak<I> {
+        Weak::new(this)
+    }
+}
+
+impl<I: FromIBinder + ?Sized> Clone for Strong<I> {
+    fn clone(&self) -> Self {
+        // Since we hold a strong reference, we should always be able to create
+        // a new strong reference to the same interface type, so try_from()
+        // should never fail here.
+        FromIBinder::try_from(self.0.as_binder()).unwrap()
+    }
+}
+
+impl<I: FromIBinder + ?Sized> Borrow<I> for Strong<I> {
+    fn borrow(&self) -> &I {
+        &self.0
+    }
+}
+
+impl<I: FromIBinder + ?Sized> AsRef<I> for Strong<I> {
+    fn as_ref(&self) -> &I {
+        &self.0
+    }
+}
+
+impl<I: FromIBinder + ?Sized> Deref for Strong<I> {
+    type Target = I;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<I: FromIBinder + fmt::Debug + ?Sized> fmt::Debug for Strong<I> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&**self, f)
+    }
+}
+
+impl<I: FromIBinder + ?Sized> Ord for Strong<I> {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.0.as_binder().cmp(&other.0.as_binder())
+    }
+}
+
+impl<I: FromIBinder + ?Sized> PartialOrd for Strong<I> {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.0.as_binder().partial_cmp(&other.0.as_binder())
+    }
+}
+
+impl<I: FromIBinder + ?Sized> PartialEq for Strong<I> {
+    fn eq(&self, other: &Self) -> bool {
+        self.0.as_binder().eq(&other.0.as_binder())
+    }
+}
+
+impl<I: FromIBinder + ?Sized> Eq for Strong<I> {}
+
+/// Weak reference to a binder object
+#[derive(Debug)]
+pub struct Weak<I: FromIBinder + ?Sized> {
+    weak_binder: WpIBinder,
+    interface_type: PhantomData<I>,
+}
+
+impl<I: FromIBinder + ?Sized> Weak<I> {
+    /// Construct a new weak reference from a strong reference
+    fn new(binder: &Strong<I>) -> Self {
+        let weak_binder = binder.as_binder().downgrade();
+        Weak {
+            weak_binder,
+            interface_type: PhantomData,
+        }
+    }
+
+    /// Upgrade this weak reference to a strong reference if the binder object
+    /// is still alive
+    pub fn upgrade(&self) -> Result<Strong<I>> {
+        self.weak_binder
+            .promote()
+            .ok_or(StatusCode::DEAD_OBJECT)
+            .and_then(FromIBinder::try_from)
+    }
+}
+
+impl<I: FromIBinder + ?Sized> Clone for Weak<I> {
+    fn clone(&self) -> Self {
+        Self {
+            weak_binder: self.weak_binder.clone(),
+            interface_type: PhantomData,
+        }
+    }
+}
+
+impl<I: FromIBinder + ?Sized> Ord for Weak<I> {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.weak_binder.cmp(&other.weak_binder)
+    }
+}
+
+impl<I: FromIBinder + ?Sized> PartialOrd for Weak<I> {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.weak_binder.partial_cmp(&other.weak_binder)
+    }
+}
+
+impl<I: FromIBinder + ?Sized> PartialEq for Weak<I> {
+    fn eq(&self, other: &Self) -> bool {
+        self.weak_binder == other.weak_binder
+    }
+}
+
+impl<I: FromIBinder + ?Sized> Eq for Weak<I> {}
+
 /// Create a function implementing a static getter for an interface class.
 ///
 /// Each binder interface (i.e. local [`Remotable`] service or remote proxy
@@ -354,12 +485,12 @@
 ///     }
 /// }
 /// ```
-pub trait FromIBinder {
+pub trait FromIBinder: Interface {
     /// Try to interpret a generic Binder object as this interface.
     ///
     /// Returns a trait object for the `Self` interface if this object
     /// implements that interface.
-    fn try_from(ibinder: SpIBinder) -> Result<Box<Self>>;
+    fn try_from(ibinder: SpIBinder) -> Result<Strong<Self>>;
 }
 
 /// Trait for transparent Rust wrappers around android C++ native types.
@@ -534,8 +665,9 @@
 
         impl $native {
             /// Create a new binder service.
-            pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> impl $interface {
-                $crate::Binder::new($native(Box::new(inner)))
+            pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> $crate::Strong<dyn $interface> {
+                let binder = $crate::Binder::new($native(Box::new(inner)));
+                $crate::Strong::new(Box::new(binder))
             }
         }
 
@@ -577,7 +709,7 @@
         }
 
         impl $crate::FromIBinder for dyn $interface {
-            fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<Box<dyn $interface>> {
+            fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<$crate::Strong<dyn $interface>> {
                 use $crate::AssociateClass;
 
                 let existing_class = ibinder.get_class();
@@ -590,7 +722,7 @@
                         // associated object as remote, because we can't cast it
                         // into a Rust service object without a matching class
                         // pointer.
-                        return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
+                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
                     }
                 }
 
@@ -600,10 +732,10 @@
                     if let Ok(service) = service {
                         // We were able to associate with our expected class and
                         // the service is local.
-                        return Ok(Box::new(service));
+                        return Ok($crate::Strong::new(Box::new(service)));
                     } else {
                         // Service is remote
-                        return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
+                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
                     }
                 }
 
@@ -633,9 +765,9 @@
             }
         }
 
-        // Convert a &dyn $interface to Box<dyn $interface>
+        /// Convert a &dyn $interface to Strong<dyn $interface>
         impl std::borrow::ToOwned for dyn $interface {
-            type Owned = Box<dyn $interface>;
+            type Owned = $crate::Strong<dyn $interface>;
             fn to_owned(&self) -> Self::Owned {
                 self.as_binder().into_interface()
                     .expect(concat!("Error cloning interface ", stringify!($interface)))
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index edfb56a..43a237a 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -107,7 +107,8 @@
 pub mod parcel;
 
 pub use crate::binder::{
-    FromIBinder, IBinder, Interface, InterfaceClass, Remotable, TransactionCode, TransactionFlags,
+    FromIBinder, IBinder, Interface, InterfaceClass, Remotable, Strong, TransactionCode,
+    TransactionFlags, Weak,
 };
 pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
 pub use native::add_service;
@@ -122,7 +123,8 @@
     pub use super::parcel::ParcelFileDescriptor;
     pub use super::{add_service, get_interface};
     pub use super::{
-        ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, WpIBinder,
+        ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, Strong, ThreadState,
+        Weak, WpIBinder,
     };
 
     /// Binder result containing a [`Status`] on error.
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 8d18fb4..f57788b 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-use crate::binder::{AsNative, FromIBinder};
+use crate::binder::{AsNative, FromIBinder, Strong};
 use crate::error::{status_result, status_t, Result, Status, StatusCode};
 use crate::parcel::Parcel;
 use crate::proxy::SpIBinder;
@@ -628,26 +628,26 @@
     }
 }
 
-impl<T: Serialize + ?Sized> Serialize for Box<T> {
+impl<T: Serialize + FromIBinder + ?Sized> Serialize for Strong<T> {
     fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
         Serialize::serialize(&**self, parcel)
     }
 }
 
-impl<T: SerializeOption + ?Sized> SerializeOption for Box<T> {
+impl<T: SerializeOption + FromIBinder + ?Sized> SerializeOption for Strong<T> {
     fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
         SerializeOption::serialize_option(this.map(|b| &**b), parcel)
     }
 }
 
-impl<T: FromIBinder + ?Sized> Deserialize for Box<T> {
+impl<T: FromIBinder + ?Sized> Deserialize for Strong<T> {
     fn deserialize(parcel: &Parcel) -> Result<Self> {
         let ibinder: SpIBinder = parcel.read()?;
         FromIBinder::try_from(ibinder)
     }
 }
 
-impl<T: FromIBinder + ?Sized> DeserializeOption for Box<T> {
+impl<T: FromIBinder + ?Sized> DeserializeOption for Strong<T> {
     fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
         let ibinder: Option<SpIBinder> = parcel.read()?;
         ibinder.map(FromIBinder::try_from).transpose()
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index e9e74c0..132e075 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -17,7 +17,7 @@
 //! Rust API for interacting with a remote binder service.
 
 use crate::binder::{
-    AsNative, FromIBinder, IBinder, Interface, InterfaceClass, TransactionCode, TransactionFlags,
+    AsNative, FromIBinder, IBinder, Interface, InterfaceClass, Strong, TransactionCode, TransactionFlags,
 };
 use crate::error::{status_result, Result, StatusCode};
 use crate::parcel::{
@@ -27,6 +27,7 @@
 use crate::sys;
 
 use std::convert::TryInto;
+use std::cmp::Ordering;
 use std::ffi::{c_void, CString};
 use std::fmt;
 use std::os::unix::io::AsRawFd;
@@ -99,7 +100,7 @@
     ///
     /// If this object does not implement the expected interface, the error
     /// `StatusCode::BAD_TYPE` is returned.
-    pub fn into_interface<I: FromIBinder + ?Sized>(self) -> Result<Box<I>> {
+    pub fn into_interface<I: FromIBinder + Interface + ?Sized>(self) -> Result<Strong<I>> {
         FromIBinder::try_from(self)
     }
 
@@ -148,6 +149,36 @@
     }
 }
 
+impl Ord for SpIBinder {
+    fn cmp(&self, other: &Self) -> Ordering {
+        let less_than = unsafe {
+            // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
+            // this pointer is always safe to pass to `AIBinder_lt` (null is
+            // also safe to pass to this function, but we should never do that).
+            sys::AIBinder_lt(self.0, other.0)
+        };
+        let greater_than = unsafe {
+            // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
+            // this pointer is always safe to pass to `AIBinder_lt` (null is
+            // also safe to pass to this function, but we should never do that).
+            sys::AIBinder_lt(other.0, self.0)
+        };
+        if !less_than && !greater_than {
+            Ordering::Equal
+        } else if less_than {
+            Ordering::Less
+        } else {
+            Ordering::Greater
+        }
+    }
+}
+
+impl PartialOrd for SpIBinder {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
 impl PartialEq for SpIBinder {
     fn eq(&self, other: &Self) -> bool {
         ptr::eq(self.0, other.0)
@@ -326,7 +357,7 @@
             // Safety: `SpIBinder` guarantees that `self` always contains a
             // valid pointer to an `AIBinder`. `recipient` can always be
             // converted into a valid pointer to an
-            // `AIBinder_DeatRecipient`. Any value is safe to pass as the
+            // `AIBinder_DeathRecipient`. Any value is safe to pass as the
             // cookie, although we depend on this value being set by
             // `get_cookie` when the death recipient callback is called.
             sys::AIBinder_linkToDeath(
@@ -342,7 +373,7 @@
             // Safety: `SpIBinder` guarantees that `self` always contains a
             // valid pointer to an `AIBinder`. `recipient` can always be
             // converted into a valid pointer to an
-            // `AIBinder_DeatRecipient`. Any value is safe to pass as the
+            // `AIBinder_DeathRecipient`. Any value is safe to pass as the
             // cookie, although we depend on this value being set by
             // `get_cookie` when the death recipient callback is called.
             sys::AIBinder_unlinkToDeath(
@@ -430,6 +461,62 @@
     }
 }
 
+impl Clone for WpIBinder {
+    fn clone(&self) -> Self {
+        let ptr = unsafe {
+            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
+            // so this pointer is always safe to pass to `AIBinder_Weak_clone`
+            // (although null is also a safe value to pass to this API).
+            //
+            // We get ownership of the returned pointer, so can construct a new
+            // WpIBinder object from it.
+            sys::AIBinder_Weak_clone(self.0)
+        };
+        assert!(!ptr.is_null(), "Unexpected null pointer from AIBinder_Weak_clone");
+        Self(ptr)
+    }
+}
+
+impl Ord for WpIBinder {
+    fn cmp(&self, other: &Self) -> Ordering {
+        let less_than = unsafe {
+            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
+            // so this pointer is always safe to pass to `AIBinder_Weak_lt`
+            // (null is also safe to pass to this function, but we should never
+            // do that).
+            sys::AIBinder_Weak_lt(self.0, other.0)
+        };
+        let greater_than = unsafe {
+            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
+            // so this pointer is always safe to pass to `AIBinder_Weak_lt`
+            // (null is also safe to pass to this function, but we should never
+            // do that).
+            sys::AIBinder_Weak_lt(other.0, self.0)
+        };
+        if !less_than && !greater_than {
+            Ordering::Equal
+        } else if less_than {
+            Ordering::Less
+        } else {
+            Ordering::Greater
+        }
+    }
+}
+
+impl PartialOrd for WpIBinder {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl PartialEq for WpIBinder {
+    fn eq(&self, other: &Self) -> bool {
+        self.cmp(other) == Ordering::Equal
+    }
+}
+
+impl Eq for WpIBinder {}
+
 impl Drop for WpIBinder {
     fn drop(&mut self) {
         unsafe {
@@ -564,7 +651,7 @@
 
 /// Retrieve an existing service for a particular interface, blocking for a few
 /// seconds if it doesn't yet exist.
-pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Box<T>> {
+pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
     let service = get_service(name);
     match service {
         Some(service) => FromIBinder::try_from(service),
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
index 8810b5d..0bf76c6 100644
--- a/libs/binder/rust/tests/Android.bp
+++ b/libs/binder/rust/tests/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 rust_test {
     name: "rustBinderTest",
     srcs: ["integration.rs"],
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index bb8c492..719229c 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -209,7 +209,7 @@
     use std::thread;
     use std::time::Duration;
 
-    use binder::{Binder, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode};
+    use binder::{Binder, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode, Strong};
 
     use super::{BnTest, ITest, ITestSameDescriptor, RUST_SERVICE_BINARY, TestService};
 
@@ -271,7 +271,7 @@
     fn trivial_client() {
         let service_name = "trivial_client_test";
         let _process = ScopedServiceProcess::new(service_name);
-        let test_client: Box<dyn ITest> =
+        let test_client: Strong<dyn ITest> =
             binder::get_interface(service_name).expect("Did not get manager binder service");
         assert_eq!(test_client.test().unwrap(), "trivial_client_test");
     }
@@ -280,7 +280,7 @@
     fn get_selinux_context() {
         let service_name = "get_selinux_context";
         let _process = ScopedServiceProcess::new(service_name);
-        let test_client: Box<dyn ITest> =
+        let test_client: Strong<dyn ITest> =
             binder::get_interface(service_name).expect("Did not get manager binder service");
         let expected_context = unsafe {
             let mut out_ptr = ptr::null_mut();
@@ -453,7 +453,7 @@
 
             let extension = maybe_extension.expect("Remote binder did not have an extension");
 
-            let extension: Box<dyn ITest> = FromIBinder::try_from(extension)
+            let extension: Strong<dyn ITest> = FromIBinder::try_from(extension)
                 .expect("Extension could not be converted to the expected interface");
 
             assert_eq!(extension.test().unwrap(), extension_name);
@@ -479,7 +479,7 @@
 
         // This should succeed although we will have to treat the service as
         // remote.
-        let _interface: Box<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
+        let _interface: Strong<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
             .expect("Could not re-interpret service as the ITestSameDescriptor interface");
     }
 
@@ -490,9 +490,60 @@
         let service_ibinder = BnTest::new_binder(TestService { s: service_name.to_string() })
             .as_binder();
 
-        let service: Box<dyn ITest> = service_ibinder.into_interface()
+        let service: Strong<dyn ITest> = service_ibinder.into_interface()
             .expect("Could not reassociate the generic ibinder");
 
         assert_eq!(service.test().unwrap(), service_name);
     }
+
+    #[test]
+    fn weak_binder_upgrade() {
+        let service_name = "testing_service";
+        let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+
+        let weak = Strong::downgrade(&service);
+
+        let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
+
+        assert_eq!(service, upgraded);
+    }
+
+    #[test]
+    fn weak_binder_upgrade_dead() {
+        let service_name = "testing_service";
+        let weak = {
+            let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+
+            Strong::downgrade(&service)
+        };
+
+        assert_eq!(weak.upgrade(), Err(StatusCode::DEAD_OBJECT));
+    }
+
+    #[test]
+    fn weak_binder_clone() {
+        let service_name = "testing_service";
+        let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+
+        let weak = Strong::downgrade(&service);
+        let cloned = weak.clone();
+        assert_eq!(weak, cloned);
+
+        let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
+        let clone_upgraded = cloned.upgrade().expect("Could not upgrade weak binder");
+
+        assert_eq!(service, upgraded);
+        assert_eq!(service, clone_upgraded);
+    }
+
+    #[test]
+    #[allow(clippy::eq_op)]
+    fn binder_ord() {
+        let service1 = BnTest::new_binder(TestService { s: "testing_service1".to_string() });
+        let service2 = BnTest::new_binder(TestService { s: "testing_service2".to_string() });
+
+        assert!(!(service1 < service1));
+        assert!(!(service1 > service1));
+        assert_eq!(service1 < service2, !(service2 < service1));
+    }
 }
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
index 70a6dc0..ce75ab7 100644
--- a/libs/binder/rust/tests/ndk_rust_interop.rs
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -37,7 +37,7 @@
 
     // The Rust class descriptor pointer will not match the NDK one, but the
     // descriptor strings match so this needs to still associate.
-    let service: Box<dyn IBinderRustNdkInteropTest> = match binder::get_interface(service_name) {
+    let service: binder::Strong<dyn IBinderRustNdkInteropTest> = match binder::get_interface(service_name) {
         Err(e) => {
             eprintln!("Could not find Ndk service {}: {:?}", service_name, e);
             return StatusCode::NAME_NOT_FOUND as c_int;
@@ -53,7 +53,7 @@
     }
 
     // Try using the binder service through the wrong interface type
-    let wrong_service: Result<Box<dyn IBinderRustNdkInteropTestOther>, StatusCode> =
+    let wrong_service: Result<binder::Strong<dyn IBinderRustNdkInteropTestOther>, StatusCode> =
         binder::get_interface(service_name);
     match wrong_service {
         Err(e) if e == StatusCode::BAD_TYPE => {}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 259417a..3bbb0b5 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "binder_test_defaults",
     cflags: [
diff --git a/libs/binder/tests/binderParcelBenchmark.cpp b/libs/binder/tests/binderParcelBenchmark.cpp
index ec69c36..26c50eb 100644
--- a/libs/binder/tests/binderParcelBenchmark.cpp
+++ b/libs/binder/tests/binderParcelBenchmark.cpp
@@ -91,56 +91,56 @@
 
   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
+  #BM_BoolVector/1         44 ns      44 ns     15630626
+  #BM_BoolVector/2         54 ns      54 ns     12900340
+  #BM_BoolVector/4         73 ns      72 ns      9749841
+  #BM_BoolVector/8        107 ns     107 ns      6503326
+  #BM_BoolVector/16       186 ns     185 ns      3773627
+  #BM_BoolVector/32       337 ns     336 ns      2083877
+  #BM_BoolVector/64       607 ns     605 ns      1154113
+  #BM_BoolVector/128     1155 ns    1151 ns       608128
+  #BM_BoolVector/256     2259 ns    2253 ns       310973
+  #BM_BoolVector/512     4469 ns    4455 ns       157277
+  #BM_ByteVector/1         41 ns      41 ns     16837425
+  #BM_ByteVector/2         41 ns      41 ns     16820726
+  #BM_ByteVector/4         38 ns      38 ns     18217813
+  #BM_ByteVector/8         38 ns      38 ns     18290298
+  #BM_ByteVector/16        38 ns      38 ns     18117817
+  #BM_ByteVector/32        38 ns      38 ns     18172385
+  #BM_ByteVector/64        41 ns      41 ns     16950055
+  #BM_ByteVector/128       53 ns      53 ns     13170749
+  #BM_ByteVector/256       69 ns      69 ns     10113626
+  #BM_ByteVector/512      106 ns     106 ns      6561936
+  #BM_CharVector/1         38 ns      38 ns     18074831
+  #BM_CharVector/2         40 ns      40 ns     17206266
+  #BM_CharVector/4         50 ns      50 ns     13785944
+  #BM_CharVector/8         67 ns      67 ns     10223316
+  #BM_CharVector/16        96 ns      96 ns      7297285
+  #BM_CharVector/32       156 ns     155 ns      4484845
+  #BM_CharVector/64       277 ns     276 ns      2536003
+  #BM_CharVector/128      520 ns     518 ns      1347070
+  #BM_CharVector/256     1006 ns    1003 ns       695952
+  #BM_CharVector/512     1976 ns    1970 ns       354673
+  #BM_Int32Vector/1        41 ns      41 ns     16951262
+  #BM_Int32Vector/2        41 ns      41 ns     16916883
+  #BM_Int32Vector/4        41 ns      41 ns     16761373
+  #BM_Int32Vector/8        42 ns      42 ns     16553179
+  #BM_Int32Vector/16       43 ns      43 ns     16200362
+  #BM_Int32Vector/32       55 ns      54 ns     12724454
+  #BM_Int32Vector/64       70 ns      69 ns     10049223
+  #BM_Int32Vector/128     107 ns     107 ns      6525796
+  #BM_Int32Vector/256     179 ns     178 ns      3922563
+  #BM_Int32Vector/512     324 ns     323 ns      2160653
+  #BM_Int64Vector/1        41 ns      41 ns     16909470
+  #BM_Int64Vector/2        41 ns      41 ns     16740788
+  #BM_Int64Vector/4        42 ns      42 ns     16564197
+  #BM_Int64Vector/8        43 ns      42 ns     16284082
+  #BM_Int64Vector/16       54 ns      54 ns     12839474
+  #BM_Int64Vector/32       69 ns      69 ns     10011010
+  #BM_Int64Vector/64      107 ns     106 ns      6557956
+  #BM_Int64Vector/128     177 ns     177 ns      3925618
+  #BM_Int64Vector/256     324 ns     323 ns      2163321
+  #BM_Int64Vector/512     613 ns     611 ns      1140418
 */
 
 static void BM_BoolVector(benchmark::State& state) {
diff --git a/libs/binder/tests/fuzzers/Android.bp b/libs/binder/tests/fuzzers/Android.bp
index 5531296..b1263e8 100644
--- a/libs/binder/tests/fuzzers/Android.bp
+++ b/libs/binder/tests/fuzzers/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "binder_fuzz_defaults",
     host_supported: true,
diff --git a/libs/binderdebug/Android.bp b/libs/binderdebug/Android.bp
index 343246a..3eeaf3e 100644
--- a/libs/binderdebug/Android.bp
+++ b/libs/binderdebug/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library {
     name: "libbinderdebug",
     vendor_available: true,
diff --git a/libs/binderdebug/tests/Android.bp b/libs/binderdebug/tests/Android.bp
index 4c06b1d..d141a05 100644
--- a/libs/binderdebug/tests/Android.bp
+++ b/libs/binderdebug/tests/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "libbinderdebug_test",
     test_suites: ["general-tests"],
diff --git a/libs/binderthreadstate/1.0/Android.bp b/libs/binderthreadstate/1.0/Android.bp
index ebdc932..99477d8 100644
--- a/libs/binderthreadstate/1.0/Android.bp
+++ b/libs/binderthreadstate/1.0/Android.bp
@@ -1,5 +1,14 @@
 // This file is autogenerated by hidl-gen -Landroidbp.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 hidl_interface {
     name: "binderthreadstateutilstest@1.0",
     root: "binderthreadstateutilstest",
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index 08c62df..0a82463 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -14,6 +14,15 @@
 
 // DO NOT ADD NEW USAGES OF THIS
 // See comments in header file.
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
     name: "libbinderthreadstateutils",
     double_loadable: true,
diff --git a/libs/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp
index bab2674..c5d3a32 100644
--- a/libs/bufferqueueconverter/Android.bp
+++ b/libs/bufferqueueconverter/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_headers {
     name: "libbufferqueueconverter_headers",
     vendor_available: true,
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index e3cd085..570af71 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library {
     name: "libtimeinstate",
     srcs: ["cputimeinstate.cpp"],
@@ -35,4 +44,3 @@
     ],
     require_root: true,
 }
-
diff --git a/libs/diskusage/Android.bp b/libs/diskusage/Android.bp
index a826306..8684061 100644
--- a/libs/diskusage/Android.bp
+++ b/libs/diskusage/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
     name: "libdiskusage",
     srcs: ["dirsize.c"],
diff --git a/libs/dumputils/Android.bp b/libs/dumputils/Android.bp
index e403d36..acda402 100644
--- a/libs/dumputils/Android.bp
+++ b/libs/dumputils/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library {
     name: "libdumputils",
 
diff --git a/libs/fakeservicemanager/Android.bp b/libs/fakeservicemanager/Android.bp
index 76518c1..47c0657 100644
--- a/libs/fakeservicemanager/Android.bp
+++ b/libs/fakeservicemanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "fakeservicemanager_defaults",
     host_supported: true,
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index dd0ae30..a0032ae 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library {
     name: "libgralloctypes",
     defaults: ["libbinder_ndk_host_user"],
diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp
index 8933dc3..6689771 100644
--- a/libs/gralloc/types/fuzzer/Android.bp
+++ b/libs/gralloc/types/fuzzer/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_fuzz {
     name: "libgralloctypes_fuzzer",
     defaults: ["libbinder_ndk_host_user"],
diff --git a/libs/gralloc/types/tests/Android.bp b/libs/gralloc/types/tests/Android.bp
index b939c1d..66eb0aa 100644
--- a/libs/gralloc/types/tests/Android.bp
+++ b/libs/gralloc/types/tests/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "GrallocTypes_test",
     shared_libs: [
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 642c5f2..a96a07a 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libgraphicsenv",
 
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index fa5044c..debd664 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -11,6 +11,15 @@
 // 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.
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_headers {
     name: "libgui_headers",
     vendor_available: true,
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index c2ec0fe..82c9268 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -55,7 +55,7 @@
     ALOGE("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
 
 void BLASTBufferItemConsumer::onDisconnect() {
-    Mutex::Autolock lock(mFrameEventHistoryMutex);
+    Mutex::Autolock lock(mMutex);
     mPreviouslyConnected = mCurrentlyConnected;
     mCurrentlyConnected = false;
     if (mPreviouslyConnected) {
@@ -66,7 +66,7 @@
 
 void BLASTBufferItemConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
                                                        FrameEventHistoryDelta* outDelta) {
-    Mutex::Autolock lock(mFrameEventHistoryMutex);
+    Mutex::Autolock lock(mMutex);
     if (newTimestamps) {
         // BufferQueueProducer only adds a new timestamp on
         // queueBuffer
@@ -90,7 +90,7 @@
                                                     const sp<Fence>& prevReleaseFence,
                                                     CompositorTiming compositorTiming,
                                                     nsecs_t latchTime, nsecs_t dequeueReadyTime) {
-    Mutex::Autolock lock(mFrameEventHistoryMutex);
+    Mutex::Autolock lock(mMutex);
 
     // if the producer is not connected, don't bother updating,
     // the next producer that connects won't access this frame event
@@ -108,7 +108,7 @@
 
 void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect) {
     bool disconnect = false;
-    Mutex::Autolock lock(mFrameEventHistoryMutex);
+    Mutex::Autolock lock(mMutex);
     while (!mDisconnectEvents.empty() && mDisconnectEvents.front() <= frameNumber) {
         disconnect = true;
         mDisconnectEvents.pop();
@@ -116,6 +116,19 @@
     if (needsDisconnect != nullptr) *needsDisconnect = disconnect;
 }
 
+void BLASTBufferItemConsumer::setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) {
+    Mutex::Autolock lock(mMutex);
+    mBLASTBufferQueue = blastbufferqueue;
+}
+
+void BLASTBufferItemConsumer::onSidebandStreamChanged() {
+    Mutex::Autolock lock(mMutex);
+    if (mBLASTBufferQueue != nullptr) {
+        sp<NativeHandle> stream = getSidebandStream();
+        mBLASTBufferQueue->setSidebandStream(stream);
+    }
+}
+
 BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
                                    int width, int height, int32_t format,
                                    bool enableTripleBuffering)
@@ -133,8 +146,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++;
@@ -143,6 +158,7 @@
     mBufferItemConsumer->setBufferFreedListener(this);
     mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
     mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
+    mBufferItemConsumer->setBlastBufferQueue(this);
 
     mTransformHint = mSurfaceControl->getTransformHint();
     mBufferItemConsumer->setTransformHint(mTransformHint);
@@ -158,6 +174,7 @@
 }
 
 BLASTBufferQueue::~BLASTBufferQueue() {
+    mBufferItemConsumer->setBlastBufferQueue(nullptr);
     if (mPendingTransactions.empty()) {
         return;
     }
@@ -555,6 +572,13 @@
     return OK;
 }
 
+void BLASTBufferQueue::setSidebandStream(const sp<NativeHandle>& stream) {
+    std::unique_lock _lock{mMutex};
+    SurfaceComposerClient::Transaction t;
+
+    t.setSidebandStream(mSurfaceControl, stream).apply();
+}
+
 sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
     std::unique_lock _lock{mMutex};
     sp<IBinder> scHandle = nullptr;
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 2ad484a..9cd3f63 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -36,9 +36,7 @@
 DisplayEventDispatcher::DisplayEventDispatcher(
         const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
         ISurfaceComposer::EventRegistrationFlags eventRegistration)
-      : mLooper(looper),
-        mReceiver(vsyncSource, eventRegistration),
-        mVsyncState(VsyncState::Unregistered) {
+      : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false) {
     ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
 }
 
@@ -68,37 +66,26 @@
 }
 
 status_t DisplayEventDispatcher::scheduleVsync() {
-    switch (mVsyncState) {
-        case VsyncState::Unregistered: {
-            ALOGV("dispatcher %p ~ Scheduling vsync.", this);
+    if (!mWaitingForVsync) {
+        ALOGV("dispatcher %p ~ Scheduling vsync.", this);
 
-            // Drain all pending events.
-            nsecs_t vsyncTimestamp;
-            PhysicalDisplayId vsyncDisplayId;
-            uint32_t vsyncCount;
-            VsyncEventData vsyncEventData;
-            if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount,
-                                     &vsyncEventData)) {
-                ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "",
-                      this, ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
-            }
+        // Drain all pending events.
+        nsecs_t vsyncTimestamp;
+        PhysicalDisplayId vsyncDisplayId;
+        uint32_t vsyncCount;
+        VsyncEventData vsyncEventData;
+        if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
+            ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
+                  ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
+        }
 
-            status_t status = mReceiver.setVsyncRate(1);
-            if (status) {
-                ALOGW("Failed to set vsync rate, status=%d", status);
-                return status;
-            }
+        status_t status = mReceiver.requestNextVsync();
+        if (status) {
+            ALOGW("Failed to request next vsync, status=%d", status);
+            return status;
+        }
 
-            mVsyncState = VsyncState::RegisteredAndWaitingForVsync;
-            break;
-        }
-        case VsyncState::Registered: {
-            mVsyncState = VsyncState::RegisteredAndWaitingForVsync;
-            break;
-        }
-        case VsyncState::RegisteredAndWaitingForVsync: {
-            break;
-        }
+        mWaitingForVsync = true;
     }
     return OK;
 }
@@ -136,23 +123,8 @@
               ", displayId=%s, count=%d, vsyncId=%" PRId64,
               this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
               vsyncEventData.id);
-        switch (mVsyncState) {
-            case VsyncState::Unregistered:
-                ALOGW("Received unexpected VSYNC event");
-                break;
-            case VsyncState::RegisteredAndWaitingForVsync:
-                mVsyncState = VsyncState::Registered;
-                dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
-                break;
-            case VsyncState::Registered:
-                status_t status = mReceiver.setVsyncRate(0);
-                if (status) {
-                    ALOGW("Failed to reset vsync rate, status=%d", status);
-                    return status;
-                }
-                mVsyncState = VsyncState::Unregistered;
-                break;
-        }
+        mWaitingForVsync = false;
+        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
     }
 
     return 1; // keep the callback
@@ -184,9 +156,9 @@
                 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
                     dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
                     break;
-                case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
-                    dispatchConfigChanged(ev.header.timestamp, ev.header.displayId,
-                                          ev.config.configId, ev.config.vsyncPeriod);
+                case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
+                    dispatchModeChanged(ev.header.timestamp, ev.header.displayId,
+                                        ev.modeChange.modeId, ev.modeChange.vsyncPeriod);
                     break;
                 case DisplayEventReceiver::DISPLAY_EVENT_NULL:
                     dispatchNullEvent(ev.header.timestamp, ev.header.displayId);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index f68f3e1..2e4f858 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -36,11 +36,12 @@
 
 #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/DynamicDisplayInfo.h>
 #include <ui/HdrCapabilities.h>
+#include <ui/StaticDisplayInfo.h>
 
 #include <utils/Log.h>
 
@@ -323,33 +324,26 @@
         return result;
     }
 
-    status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) override {
+    status_t getStaticDisplayInfo(const sp<IBinder>& display,
+                                  ui::StaticDisplayInfo* info) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
-        remote()->transact(BnSurfaceComposer::GET_DISPLAY_INFO, data, &reply);
+        remote()->transact(BnSurfaceComposer::GET_STATIC_DISPLAY_INFO, data, &reply);
         const status_t result = reply.readInt32();
         if (result != NO_ERROR) return result;
         return reply.read(*info);
     }
 
-    status_t getDisplayConfigs(const sp<IBinder>& display,
-                               Vector<DisplayConfig>* configs) override {
+    status_t getDynamicDisplayInfo(const sp<IBinder>& display,
+                                   ui::DynamicDisplayInfo* info) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
-        remote()->transact(BnSurfaceComposer::GET_DISPLAY_CONFIGS, data, &reply);
+        remote()->transact(BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO, 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));
-            }
-        }
-        return result;
+        if (result != NO_ERROR) return result;
+        return reply.read(*info);
     }
 
     status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats) override {
@@ -366,44 +360,6 @@
         return result;
     }
 
-    int getActiveConfig(const sp<IBinder>& display) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-        remote()->transact(BnSurfaceComposer::GET_ACTIVE_CONFIG, data, &reply);
-        return reply.readInt32();
-    }
-
-    status_t getDisplayColorModes(const sp<IBinder>& display,
-                                  Vector<ColorMode>* outColorModes) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("getDisplayColorModes failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("getDisplayColorModes failed to writeStrongBinder: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_COLOR_MODES, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("getDisplayColorModes failed to transact: %d", result);
-            return result;
-        }
-        result = static_cast<status_t>(reply.readInt32());
-        if (result == NO_ERROR) {
-            size_t numModes = reply.readUint32();
-            outColorModes->clear();
-            outColorModes->resize(numModes);
-            for (size_t i = 0; i < numModes; ++i) {
-                outColorModes->replaceAt(static_cast<ColorMode>(reply.readInt32()), i);
-            }
-        }
-        return result;
-    }
-
     status_t getDisplayNativePrimaries(const sp<IBinder>& display,
                                        ui::DisplayPrimaries& primaries) override {
         Parcel data, reply;
@@ -430,26 +386,6 @@
         return result;
     }
 
-    ColorMode getActiveColorMode(const sp<IBinder>& display) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("getActiveColorMode failed to writeInterfaceToken: %d", result);
-            return static_cast<ColorMode>(result);
-        }
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("getActiveColorMode failed to writeStrongBinder: %d", result);
-            return static_cast<ColorMode>(result);
-        }
-        result = remote()->transact(BnSurfaceComposer::GET_ACTIVE_COLOR_MODE, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("getActiveColorMode failed to transact: %d", result);
-            return static_cast<ColorMode>(result);
-        }
-        return static_cast<ColorMode>(reply.readInt32());
-    }
-
     status_t setActiveColorMode(const sp<IBinder>& display, ColorMode colorMode) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -581,28 +517,6 @@
         return reply.readInt32();
     }
 
-    status_t getHdrCapabilities(const sp<IBinder>& display,
-                                HdrCapabilities* outCapabilities) const override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        status_t result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("getHdrCapabilities failed to writeStrongBinder: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::GET_HDR_CAPABILITIES,
-                data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("getHdrCapabilities failed to transact: %d", result);
-            return result;
-        }
-        result = reply.readInt32();
-        if (result == NO_ERROR) {
-            result = reply.read(*outCapabilities);
-        }
-        return result;
-    }
-
     status_t enableVSyncInjections(bool enable) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -882,71 +796,72 @@
         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,
+                                        ui::DisplayModeId 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,
+                                        ui::DisplayModeId* outDefaultMode,
+                                        bool* outAllowGroupSwitching,
+                                        float* outPrimaryRefreshRateMin,
+                                        float* outPrimaryRefreshRateMax,
+                                        float* outAppRequestRefreshRateMin,
+                                        float* outAppRequestRefreshRateMax) override {
+        if (!outDefaultMode || !outAllowGroupSwitching || !outPrimaryRefreshRateMin ||
             !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin ||
             !outAppRequestRefreshRateMax) {
             return BAD_VALUE;
@@ -954,50 +869,54 @@
         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);
+
+        result = reply.readInt32(outDefaultMode);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read defaultConfig: %d", result);
+            ALOGE("getDesiredDisplayModeSpecs failed to read defaultMode: %d", result);
             return result;
         }
+        if (*outDefaultMode < 0) {
+            ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, *outDefaultMode);
+            return BAD_VALUE;
+        }
+
         result = reply.readBool(outAllowGroupSwitching);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read allowGroupSwitching: %d", result);
+            ALOGE("getDesiredDisplayModeSpecs failed to read allowGroupSwitching: %d", result);
             return result;
         }
         result = reply.readFloat(outPrimaryRefreshRateMin);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMin: %d", result);
+            ALOGE("getDesiredDisplayModeSpecs failed to read primaryRefreshRateMin: %d", result);
             return result;
         }
         result = reply.readFloat(outPrimaryRefreshRateMax);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMax: %d", result);
+            ALOGE("getDesiredDisplayModeSpecs failed to read primaryRefreshRateMax: %d", result);
             return result;
         }
         result = reply.readFloat(outAppRequestRefreshRateMin);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMin: %d",
-                  result);
+            ALOGE("getDesiredDisplayModeSpecs failed to read appRequestRefreshRateMin: %d", result);
             return result;
         }
         result = reply.readFloat(outAppRequestRefreshRateMax);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMax: %d",
-                  result);
+            ALOGE("getDesiredDisplayModeSpecs failed to read appRequestRefreshRateMax: %d", result);
             return result;
         }
         return reply.readInt32();
@@ -1232,6 +1151,18 @@
         }
         return reply.readInt32();
     }
+
+    status_t getExtraBufferCount(int* extraBuffers) const override {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        status_t err = remote()->transact(BnSurfaceComposer::GET_EXTRA_BUFFER_COUNT, data, &reply);
+        if (err != NO_ERROR) {
+            ALOGE("getExtraBufferCount failed to read data:  %s (%d)", strerror(-err), err);
+            return err;
+        }
+
+        return reply.readInt32(extraBuffers);
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -1421,28 +1352,24 @@
             }
             return NO_ERROR;
         }
-        case GET_DISPLAY_INFO: {
+        case GET_STATIC_DISPLAY_INFO: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            DisplayInfo info;
+            ui::StaticDisplayInfo info;
             const sp<IBinder> display = data.readStrongBinder();
-            const status_t result = getDisplayInfo(display, &info);
-            reply->writeInt32(result);
+            const status_t result = getStaticDisplayInfo(display, &info);
+            SAFE_PARCEL(reply->writeInt32, result);
             if (result != NO_ERROR) return result;
-            return reply->write(info);
+            SAFE_PARCEL(reply->write, info);
+            return NO_ERROR;
         }
-        case GET_DISPLAY_CONFIGS: {
+        case GET_DYNAMIC_DISPLAY_INFO: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            Vector<DisplayConfig> configs;
+            ui::DynamicDisplayInfo info;
             const sp<IBinder> display = data.readStrongBinder();
-            const status_t result = getDisplayConfigs(display, &configs);
-            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));
-                }
-            }
+            const status_t result = getDynamicDisplayInfo(display, &info);
+            SAFE_PARCEL(reply->writeInt32, result);
+            if (result != NO_ERROR) return result;
+            SAFE_PARCEL(reply->write, info);
             return NO_ERROR;
         }
         case GET_DISPLAY_STATS: {
@@ -1457,32 +1384,6 @@
             }
             return NO_ERROR;
         }
-        case GET_ACTIVE_CONFIG: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = data.readStrongBinder();
-            int id = getActiveConfig(display);
-            reply->writeInt32(id);
-            return NO_ERROR;
-        }
-        case GET_DISPLAY_COLOR_MODES: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            Vector<ColorMode> colorModes;
-            sp<IBinder> display = nullptr;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("getDisplayColorModes failed to readStrongBinder: %d", result);
-                return result;
-            }
-            result = getDisplayColorModes(display, &colorModes);
-            reply->writeInt32(result);
-            if (result == NO_ERROR) {
-                reply->writeUint32(static_cast<uint32_t>(colorModes.size()));
-                for (size_t i = 0; i < colorModes.size(); ++i) {
-                    reply->writeInt32(static_cast<int32_t>(colorModes[i]));
-                }
-            }
-            return NO_ERROR;
-        }
         case GET_DISPLAY_NATIVE_PRIMARIES: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             ui::DisplayPrimaries primaries;
@@ -1503,18 +1404,6 @@
 
             return NO_ERROR;
         }
-        case GET_ACTIVE_COLOR_MODE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = nullptr;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("getActiveColorMode failed to readStrongBinder: %d", result);
-                return result;
-            }
-            ColorMode colorMode = getActiveColorMode(display);
-            result = reply->writeInt32(static_cast<int32_t>(colorMode));
-            return result;
-        }
         case SET_ACTIVE_COLOR_MODE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> display = nullptr;
@@ -1624,23 +1513,6 @@
             setPowerMode(display, mode);
             return NO_ERROR;
         }
-        case GET_HDR_CAPABILITIES: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = nullptr;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("getHdrCapabilities failed to readStrongBinder: %d",
-                        result);
-                return result;
-            }
-            HdrCapabilities capabilities;
-            result = getHdrCapabilities(display, &capabilities);
-            reply->writeInt32(result);
-            if (result == NO_ERROR) {
-                reply->write(capabilities);
-            }
-            return NO_ERROR;
-        }
         case ENABLE_VSYNC_INJECTIONS: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             bool enable = false;
@@ -1844,56 +1716,58 @@
             }
             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);
+            ui::DisplayModeId 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, defaultMode, allowGroupSwitching,
+                                                primaryRefreshRateMin, primaryRefreshRateMax,
+                                                appRequestRefreshRateMin, appRequestRefreshRateMax);
             if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayConfigSpecs: failed to call setDesiredDisplayConfigSpecs: "
+                ALOGE("setDesiredDisplayModeSpecs: failed to call setDesiredDisplayModeSpecs: "
                       "%d",
                       result);
                 return result;
@@ -1901,10 +1775,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;
+            ui::DisplayModeId defaultMode;
             bool allowGroupSwitching;
             float primaryRefreshRateMin;
             float primaryRefreshRateMax;
@@ -1912,49 +1786,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(defaultMode);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultConfig: %d", result);
+                ALOGE("getDesiredDisplayModeSpecs: failed to write defaultMode: %d", result);
                 return result;
             }
             result = reply->writeBool(allowGroupSwitching);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write allowGroupSwitching: %d",
+                ALOGE("getDesiredDisplayModeSpecs: failed to write allowGroupSwitching: %d",
                       result);
                 return result;
             }
             result = reply->writeFloat(primaryRefreshRateMin);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMin: %d",
+                ALOGE("getDesiredDisplayModeSpecs: failed to write primaryRefreshRateMin: %d",
                       result);
                 return result;
             }
             result = reply->writeFloat(primaryRefreshRateMax);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMax: %d",
+                ALOGE("getDesiredDisplayModeSpecs: failed to write primaryRefreshRateMax: %d",
                       result);
                 return result;
             }
             result = reply->writeFloat(appRequestRefreshRateMin);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMin: %d",
+                ALOGE("getDesiredDisplayModeSpecs: failed to write appRequestRefreshRateMin: %d",
                       result);
                 return result;
             }
             result = reply->writeFloat(appRequestRefreshRateMax);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMax: %d",
+                ALOGE("getDesiredDisplayModeSpecs: failed to write appRequestRefreshRateMax: %d",
                       result);
                 return result;
             }
@@ -2101,6 +1975,16 @@
             SAFE_PARCEL(reply->writeInt32, priority);
             return NO_ERROR;
         }
+        case GET_EXTRA_BUFFER_COUNT: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            int extraBuffers = 0;
+            int err = getExtraBufferCount(&extraBuffers);
+            if (err != NO_ERROR) {
+                return err;
+            }
+            SAFE_PARCEL(reply->writeInt32, extraBuffers);
+            return NO_ERROR;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
index cdde9a2..e707684 100644
--- a/libs/gui/LayerDebugInfo.cpp
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -61,6 +61,7 @@
     RETURN_ON_ERROR(parcel->writeBool(mRefreshPending));
     RETURN_ON_ERROR(parcel->writeBool(mIsOpaque));
     RETURN_ON_ERROR(parcel->writeBool(mContentDirty));
+    RETURN_ON_ERROR(parcel->write(mStretchEffect));
     return NO_ERROR;
 }
 
@@ -105,6 +106,7 @@
     RETURN_ON_ERROR(parcel->readBool(&mRefreshPending));
     RETURN_ON_ERROR(parcel->readBool(&mIsOpaque));
     RETURN_ON_ERROR(parcel->readBool(&mContentDirty));
+    RETURN_ON_ERROR(parcel->read(mStretchEffect));
     return NO_ERROR;
 }
 
@@ -115,6 +117,12 @@
     info.mTransparentRegion.dump(result, "TransparentRegion");
     info.mVisibleRegion.dump(result, "VisibleRegion");
     info.mSurfaceDamageRegion.dump(result, "SurfaceDamageRegion");
+    if (info.mStretchEffect.hasEffect()) {
+        const auto& se = info.mStretchEffect;
+        StringAppendF(&result, "  StretchEffect area=[%f, %f, %f, %f] vec=(%f, %f) maxAmount=%f\n",
+                      se.area.left, se.area.top, se.area.right, se.area.bottom, se.vectorX,
+                      se.vectorY, se.maxAmount);
+    }
 
     StringAppendF(&result, "      layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ",
                   info.mLayerStack, info.mZ, static_cast<double>(info.mX),
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index fff3305..288bf92 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -167,6 +167,9 @@
         SAFE_PARCEL(output.writeInt32, region.right);
         SAFE_PARCEL(output.writeInt32, region.bottom);
     }
+
+    SAFE_PARCEL(output.write, stretchEffect);
+
     return NO_ERROR;
 }
 
@@ -290,6 +293,9 @@
         SAFE_PARCEL(input.readInt32, &region.bottom);
         blurRegions.push_back(region);
     }
+
+    SAFE_PARCEL(input.read, stretchEffect);
+
     return NO_ERROR;
 }
 
@@ -542,6 +548,10 @@
         what |= eAutoRefreshChanged;
         autoRefresh = other.autoRefresh;
     }
+    if (other.what & eStretchChanged) {
+        what |= eStretchChanged;
+        stretchEffect = other.stretchEffect;
+    }
     if ((other.what & what) != other.what) {
         ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
               "other.what=0x%" PRIu64 " what=0x%" PRIu64,
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 59ad8d2..6de3e97 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -34,9 +34,9 @@
 #include <utils/NativeHandle.h>
 
 #include <ui/DisplayStatInfo.h>
+#include <ui/DynamicDisplayInfo.h>
 #include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
-#include <ui/HdrCapabilities.h>
 #include <ui/Region.h>
 
 #include <gui/BufferItem.h>
@@ -48,7 +48,6 @@
 
 namespace android {
 
-using ui::ColorMode;
 using ui::Dataspace;
 
 namespace {
@@ -361,15 +360,12 @@
         return NAME_NOT_FOUND;
     }
 
-    HdrCapabilities hdrCapabilities;
-    status_t err =
-        composerService()->getHdrCapabilities(display, &hdrCapabilities);
-
-    if (err)
+    ui::DynamicDisplayInfo info;
+    if (status_t err = composerService()->getDynamicDisplayInfo(display, &info); err != NO_ERROR) {
         return err;
+    }
 
-    *supported = !hdrCapabilities.getSupportedHdrTypes().empty();
-
+    *supported = !info.hdrCapabilities.getSupportedHdrTypes().empty();
     return NO_ERROR;
 }
 
@@ -1499,6 +1495,9 @@
     case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO:
         res = dispatchSetFrameTimelineInfo(args);
         break;
+    case NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT:
+        res = dispatchGetExtraBufferCount(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -1815,6 +1814,14 @@
     return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId});
 }
 
+int Surface::dispatchGetExtraBufferCount(va_list args) {
+    ATRACE_CALL();
+    auto extraBuffers = static_cast<int*>(va_arg(args, int*));
+
+    ALOGV("Surface::dispatchGetExtraBufferCount");
+    return getExtraBufferCount(extraBuffers);
+}
+
 bool Surface::transformToDisplayInverse() {
     return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
             NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
@@ -2584,4 +2591,8 @@
     return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo);
 }
 
+status_t Surface::getExtraBufferCount(int* extraBuffers) const {
+    return composerService()->getExtraBufferCount(extraBuffers);
+}
+
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 550803d..1a643c2 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -39,7 +39,8 @@
 #include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
+#include <ui/DynamicDisplayInfo.h>
 
 #ifndef NO_INPUT
 #include <input/InputWindow.h>
@@ -194,6 +195,25 @@
     }
 }
 
+void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie,
+        sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mSurfaceStatsListeners.insert({surfaceControl->getHandle(),
+            SurfaceStatsCallbackEntry(context, cookie, listener)});
+}
+
+void TransactionCompletedListener::removeSurfaceStatsListener(void* context, void* cookie) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    for (auto it = mSurfaceStatsListeners.begin(); it != mSurfaceStatsListeners.end();) {
+        auto [itContext, itCookie, itListener] = it->second;
+        if (itContext == context && itCookie == cookie) {
+            it = mSurfaceStatsListeners.erase(it);
+        } else {
+            it++;
+        }
+    }
+}
+
 void TransactionCompletedListener::addSurfaceControlToCallbacks(
         const sp<SurfaceControl>& surfaceControl,
         const std::unordered_set<CallbackId>& callbackIds) {
@@ -210,6 +230,7 @@
 void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
     std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
     std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
+    std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry> surfaceListeners;
     {
         std::lock_guard<std::mutex> lock(mMutex);
 
@@ -226,6 +247,7 @@
          */
         callbacksMap = mCallbacks;
         jankListenersMap = mJankListeners;
+        surfaceListeners = mSurfaceStatsListeners;
         for (const auto& transactionStats : listenerStats.transactionStats) {
             for (auto& callbackId : transactionStats.callbackIds) {
                 mCallbacks.erase(callbackId);
@@ -259,9 +281,16 @@
                              surfaceControlStats);
         }
         for (const auto& surfaceStats : transactionStats.surfaceStats) {
+            auto listenerRange = surfaceListeners.equal_range(surfaceStats.surfaceControl);
+            for (auto it = listenerRange.first; it != listenerRange.second; it++) {
+                auto entry = it->second;
+                entry.callback(entry.context, transactionStats.latchTime,
+                    transactionStats.presentFence, surfaceStats);
+            }
+
             if (surfaceStats.jankData.empty()) continue;
-            for (auto it = jankListenersMap.find(surfaceStats.surfaceControl);
-                    it != jankListenersMap.end(); it++) {
+            auto jankRange = jankListenersMap.equal_range(surfaceStats.surfaceControl);
+            for (auto it = jankRange.first; it != jankRange.second; it++) {
                 it->second->onJankDataAvailable(surfaceStats.jankData);
             }
         }
@@ -1569,6 +1598,23 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setStretchEffect(
+        const sp<SurfaceControl>& sc, float left, float top, float right, float bottom, float vecX,
+        float vecY, float maxAmount) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+
+    s->what |= layer_state_t::eStretchChanged;
+    s->stretchEffect = StretchEffect{.area = {left, top, right, bottom},
+                                     .vectorX = vecX,
+                                     .vectorY = vecY,
+                                     .maxAmount = maxAmount};
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -1798,61 +1844,54 @@
     return ComposerService::getComposerService()->getDisplayState(display, state);
 }
 
-status_t SurfaceComposerClient::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) {
-    return ComposerService::getComposerService()->getDisplayInfo(display, info);
+status_t SurfaceComposerClient::getStaticDisplayInfo(const sp<IBinder>& display,
+                                                     ui::StaticDisplayInfo* info) {
+    return ComposerService::getComposerService()->getStaticDisplayInfo(display, info);
 }
 
-status_t SurfaceComposerClient::getDisplayConfigs(const sp<IBinder>& display,
-                                                  Vector<DisplayConfig>* configs) {
-    return ComposerService::getComposerService()->getDisplayConfigs(display, configs);
+status_t SurfaceComposerClient::getDynamicDisplayInfo(const sp<IBinder>& display,
+                                                      ui::DynamicDisplayInfo* info) {
+    return ComposerService::getComposerService()->getDynamicDisplayInfo(display, info);
 }
 
-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) {
+    ui::DynamicDisplayInfo info;
+    status_t result = getDynamicDisplayInfo(display, &info);
     if (result != NO_ERROR) {
         return result;
     }
 
-    int activeId = getActiveConfig(display);
-    if (activeId < 0) {
-        ALOGE("No active configuration found");
-        return NAME_NOT_FOUND;
+    if (const auto activeMode = info.getActiveDisplayMode()) {
+        *mode = *activeMode;
+        return NO_ERROR;
     }
 
-    *config = configs[static_cast<size_t>(activeId)];
-    return NO_ERROR;
+    ALOGE("Active display mode not found.");
+    return NAME_NOT_FOUND;
 }
 
-int SurfaceComposerClient::getActiveConfig(const sp<IBinder>& display) {
-    return ComposerService::getComposerService()->getActiveConfig(display);
-}
-
-status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(
-        const sp<IBinder>& displayToken, int32_t defaultConfig, bool allowGroupSwitching,
+status_t SurfaceComposerClient::setDesiredDisplayModeSpecs(
+        const sp<IBinder>& displayToken, ui::DisplayModeId 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,
-        float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
-        float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) {
+status_t SurfaceComposerClient::getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+                                                           ui::DisplayModeId* outDefaultMode,
+                                                           bool* outAllowGroupSwitching,
+                                                           float* outPrimaryRefreshRateMin,
+                                                           float* outPrimaryRefreshRateMax,
+                                                           float* outAppRequestRefreshRateMin,
+                                                           float* outAppRequestRefreshRateMax) {
     return ComposerService::getComposerService()
-            ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outAllowGroupSwitching,
-                                           outPrimaryRefreshRateMin, outPrimaryRefreshRateMax,
-                                           outAppRequestRefreshRateMin,
-                                           outAppRequestRefreshRateMax);
-}
-
-status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
-        Vector<ColorMode>* outColorModes) {
-    return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes);
+            ->getDesiredDisplayModeSpecs(displayToken, outDefaultMode, outAllowGroupSwitching,
+                                         outPrimaryRefreshRateMin, outPrimaryRefreshRateMax,
+                                         outAppRequestRefreshRateMin, outAppRequestRefreshRateMax);
 }
 
 status_t SurfaceComposerClient::getDisplayNativePrimaries(const sp<IBinder>& display,
@@ -1860,10 +1899,6 @@
     return ComposerService::getComposerService()->getDisplayNativePrimaries(display, outPrimaries);
 }
 
-ColorMode SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) {
-    return ComposerService::getComposerService()->getActiveColorMode(display);
-}
-
 status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display,
         ColorMode colorMode) {
     return ComposerService::getComposerService()->setActiveColorMode(display, colorMode);
@@ -1916,12 +1951,6 @@
     return ComposerService::getComposerService()->getAnimationFrameStats(outStats);
 }
 
-status_t SurfaceComposerClient::getHdrCapabilities(const sp<IBinder>& display,
-        HdrCapabilities* outCapabilities) {
-    return ComposerService::getComposerService()->getHdrCapabilities(display,
-            outCapabilities);
-}
-
 status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
                                                                       ui::PixelFormat* outFormat,
                                                                       ui::Dataspace* outDataspace,
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index e842382..1dcfe2e 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -30,9 +30,9 @@
 
 #include <binder/IPCThreadState.h>
 
-#include <ui/DisplayInfo.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/Rect.h>
+#include <ui/StaticDisplayInfo.h>
 
 #include <gui/BufferQueueCore.h>
 #include <gui/ISurfaceComposer.h>
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index bccb71b..dd8e714 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -32,6 +32,7 @@
 
 namespace android {
 
+class BLASTBufferQueue;
 class BufferItemConsumer;
 
 class BLASTBufferItemConsumer : public BufferItemConsumer {
@@ -40,27 +41,32 @@
                             int bufferCount, bool controlledByApp)
           : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
             mCurrentlyConnected(false),
-            mPreviouslyConnected(false) {}
+            mPreviouslyConnected(false),
+            mBLASTBufferQueue(nullptr) {}
 
     void onDisconnect() override;
     void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
-                                  FrameEventHistoryDelta* outDelta) override
-            REQUIRES(mFrameEventHistoryMutex);
+                                  FrameEventHistoryDelta* outDelta) override REQUIRES(mMutex);
     void updateFrameTimestamps(uint64_t frameNumber, nsecs_t refreshStartTime,
                                const sp<Fence>& gpuCompositionDoneFence,
                                const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
                                CompositorTiming compositorTiming, nsecs_t latchTime,
-                               nsecs_t dequeueReadyTime) REQUIRES(mFrameEventHistoryMutex);
+                               nsecs_t dequeueReadyTime) REQUIRES(mMutex);
     void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect);
+    void setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) REQUIRES(mMutex);
+
+protected:
+    void onSidebandStreamChanged() override REQUIRES(mMutex);
 
 private:
     uint64_t mCurrentFrameNumber = 0;
 
-    Mutex mFrameEventHistoryMutex;
-    ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mFrameEventHistoryMutex);
-    std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mFrameEventHistoryMutex);
-    bool mCurrentlyConnected GUARDED_BY(mFrameEventHistoryMutex);
-    bool mPreviouslyConnected GUARDED_BY(mFrameEventHistoryMutex);
+    Mutex mMutex;
+    ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mMutex);
+    std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mMutex);
+    bool mCurrentlyConnected GUARDED_BY(mMutex);
+    bool mPreviouslyConnected GUARDED_BY(mMutex);
+    BLASTBufferQueue* mBLASTBufferQueue GUARDED_BY(mMutex);
 };
 
 class BLASTBufferQueue
@@ -94,6 +100,8 @@
     status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
     status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
 
+    void setSidebandStream(const sp<NativeHandle>& stream);
+
     virtual ~BLASTBufferQueue();
 
 private:
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 4175a49..d74c2ba 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -52,20 +52,7 @@
 private:
     sp<Looper> mLooper;
     DisplayEventReceiver mReceiver;
-    // The state of vsync event registration and whether the client is expecting
-    // an event or not.
-    enum class VsyncState {
-        // The dispatcher is not registered for vsync events.
-        Unregistered,
-        // The dispatcher is registered to receive vsync events but should not dispatch it to the
-        // client as the client is not expecting a vsync event.
-        Registered,
-
-        // The dispatcher is registered to receive vsync events and supposed to dispatch it to
-        // the client.
-        RegisteredAndWaitingForVsync,
-    };
-    VsyncState mVsyncState;
+    bool mWaitingForVsync;
 
     std::vector<FrameRateOverride> mFrameRateOverrides;
 
@@ -73,8 +60,8 @@
                                VsyncEventData vsyncEventData) = 0;
     virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
                                  bool connected) = 0;
-    virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
-                                       int32_t configId, nsecs_t vsyncPeriod) = 0;
+    virtual void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
+                                     nsecs_t vsyncPeriod) = 0;
     // AChoreographer-specific hook for processing null-events so that looper
     // can be properly poked.
     virtual void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) = 0;
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 3191fc9..7179a20 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -52,7 +52,7 @@
     enum {
         DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
         DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
-        DISPLAY_EVENT_CONFIG_CHANGED = fourcc('c', 'o', 'n', 'f'),
+        DISPLAY_EVENT_MODE_CHANGE = fourcc('m', 'o', 'd', 'e'),
         DISPLAY_EVENT_NULL = fourcc('n', 'u', 'l', 'l'),
         DISPLAY_EVENT_FRAME_RATE_OVERRIDE = fourcc('r', 'a', 't', 'e'),
         DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH = fourcc('f', 'l', 's', 'h'),
@@ -82,8 +82,8 @@
             bool connected;
         };
 
-        struct Config {
-            int32_t configId;
+        struct ModeChange {
+            int32_t modeId;
             nsecs_t vsyncPeriod __attribute__((aligned(8)));
         };
 
@@ -96,7 +96,7 @@
         union {
             VSync vsync;
             Hotplug hotplug;
-            Config config;
+            ModeChange modeChange;
             FrameRateOverride frameRateOverride;
         };
     };
@@ -106,7 +106,7 @@
      * DisplayEventReceiver creates and registers an event connection with
      * SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate
      * or requestNextVsync to receive them.
-     * To receive ConfigChanged and/or FrameRateOverrides events specify this in
+     * To receive ModeChanged and/or FrameRateOverrides events specify this in
      * the constructor. Other events start being delivered immediately.
      */
     explicit DisplayEventReceiver(
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 81ff6b0..d0ab480 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -33,6 +33,7 @@
 
 #include <ui/ConfigStoreTypes.h>
 #include <ui/DisplayId.h>
+#include <ui/DisplayMode.h>
 #include <ui/DisplayedFrameStats.h>
 #include <ui/FrameStats.h>
 #include <ui/GraphicBuffer.h>
@@ -54,8 +55,6 @@
 struct client_cache_t;
 struct ComposerState;
 struct DisplayCaptureArgs;
-struct DisplayConfig;
-struct DisplayInfo;
 struct DisplayStatInfo;
 struct DisplayState;
 struct InputWindowCommands;
@@ -73,7 +72,10 @@
 
 namespace ui {
 
+struct DisplayMode;
 struct DisplayState;
+struct DynamicDisplayInfo;
+struct StaticDisplayInfo;
 
 } // namespace ui
 
@@ -112,7 +114,7 @@
     };
 
     enum class EventRegistration {
-        configChanged = 1 << 0,
+        modeChanged = 1 << 0,
         frameRateOverride = 1 << 1,
     };
 
@@ -202,26 +204,17 @@
     virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*) = 0;
 
     /**
-     * Get immutable information about given physical display.
+     * Gets immutable information about given physical display.
      */
-    virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*) = 0;
+    virtual status_t getStaticDisplayInfo(const sp<IBinder>& display, ui::StaticDisplayInfo*) = 0;
 
     /**
-     * Get configurations supported by given physical display.
+     * Gets dynamic information about given physical display.
      */
-    virtual status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>*) = 0;
+    virtual status_t getDynamicDisplayInfo(const sp<IBinder>& display, ui::DynamicDisplayInfo*) = 0;
 
-    /**
-     * Get the index into configurations returned by getDisplayConfigs,
-     * corresponding to the active configuration.
-     */
-    virtual int getActiveConfig(const sp<IBinder>& display) = 0;
-
-    virtual status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<ui::ColorMode>* outColorModes) = 0;
     virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display,
             ui::DisplayPrimaries& primaries) = 0;
-    virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display) = 0;
     virtual status_t setActiveColorMode(const sp<IBinder>& display,
             ui::ColorMode colorMode) = 0;
 
@@ -296,13 +289,6 @@
      */
     virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0;
 
-    /* Gets the supported HDR capabilities of the given display.
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t getHdrCapabilities(const sp<IBinder>& display,
-            HdrCapabilities* outCapabilities) const = 0;
-
     virtual status_t enableVSyncInjections(bool enable) = 0;
 
     virtual status_t injectVSync(nsecs_t when) = 0;
@@ -386,34 +372,32 @@
     /* 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 corresponds to an ID of mode in the list
+     * of supported modes returned from getDynamicDisplayInfo().
      */
-    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, ui::DisplayModeId 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,
+                                                ui::DisplayModeId* outDefaultMode,
+                                                bool* outAllowGroupSwitching,
+                                                float* outPrimaryRefreshRateMin,
+                                                float* outPrimaryRefreshRateMax,
+                                                float* outAppRequestRefreshRateMin,
+                                                float* outAppRequestRefreshRateMax) = 0;
     /*
      * Gets whether brightness operations are supported on a display.
      *
@@ -508,6 +492,24 @@
      * Gets priority of the RenderEngine in SurfaceFlinger.
      */
     virtual int getGPUContextPriority() = 0;
+
+    /**
+     * Gets the extra buffers a client would need to allocate if it passes
+     * the Choreographer#getVsyncId with its buffers.
+     *
+     * When Choreographer#getVsyncId is passed to SurfaceFlinger, it is used
+     * as an indication of when to latch the buffer. SurfaceFlinger will make
+     * sure that it will give the app at least the time configured as the
+     * 'appDuration' before trying to latch the buffer.
+     *
+     * The total buffers needed for a given configuration is basically the
+     * numbers of vsyncs a single buffer is used across the stack. For the default
+     * configuration a buffer is held ~1 vsync by the app, ~1 vsync by SurfaceFlinger
+     * and 1 vsync by the display. The extra buffers are calculated as the
+     * number of additional buffers on top of the 3 buffers already allocated
+     * by the app.
+     */
+    virtual status_t getExtraBufferCount(int* extraBuffers) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -519,7 +521,7 @@
         // Java by ActivityManagerService.
         BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
         CREATE_CONNECTION,
-        GET_DISPLAY_INFO,
+        GET_STATIC_DISPLAY_INFO,
         CREATE_DISPLAY_EVENT_CONNECTION,
         CREATE_DISPLAY,
         DESTROY_DISPLAY,
@@ -527,8 +529,8 @@
         SET_TRANSACTION_STATE,
         AUTHENTICATE_SURFACE,
         GET_SUPPORTED_FRAME_TIMESTAMPS,
-        GET_DISPLAY_CONFIGS,
-        GET_ACTIVE_CONFIG,
+        GET_DISPLAY_MODES,       // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        GET_ACTIVE_DISPLAY_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
         GET_DISPLAY_STATE,
         CAPTURE_DISPLAY,
         CAPTURE_LAYERS,
@@ -536,9 +538,9 @@
         GET_ANIMATION_FRAME_STATS,
         SET_POWER_MODE,
         GET_DISPLAY_STATS,
-        GET_HDR_CAPABILITIES,
-        GET_DISPLAY_COLOR_MODES,
-        GET_ACTIVE_COLOR_MODE,
+        GET_HDR_CAPABILITIES,    // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        GET_ACTIVE_COLOR_MODE,   // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
         SET_ACTIVE_COLOR_MODE,
         ENABLE_VSYNC_INJECTIONS,
         INJECT_VSYNC,
@@ -554,8 +556,8 @@
         GET_PHYSICAL_DISPLAY_IDS,
         ADD_REGION_SAMPLING_LISTENER,
         REMOVE_REGION_SAMPLING_LISTENER,
-        SET_DESIRED_DISPLAY_CONFIG_SPECS,
-        GET_DESIRED_DISPLAY_CONFIG_SPECS,
+        SET_DESIRED_DISPLAY_MODE_SPECS,
+        GET_DESIRED_DISPLAY_MODE_SPECS,
         GET_DISPLAY_BRIGHTNESS_SUPPORT,
         SET_DISPLAY_BRIGHTNESS,
         CAPTURE_DISPLAY_BY_ID,
@@ -570,6 +572,8 @@
         SET_FRAME_TIMELINE_INFO,
         ADD_TRANSACTION_TRACE_LISTENER,
         GET_GPU_CONTEXT_PRIORITY,
+        GET_EXTRA_BUFFER_COUNT,
+        GET_DYNAMIC_DISPLAY_INFO,
         // Always append new enum to the end.
     };
 
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
index 66a7b4d..8b7d32c 100644
--- a/libs/gui/include/gui/LayerDebugInfo.h
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -20,6 +20,7 @@
 
 #include <ui/PixelFormat.h>
 #include <ui/Region.h>
+#include <ui/StretchEffect.h>
 
 #include <string>
 #include <math/vec4.h>
@@ -66,6 +67,7 @@
     bool mRefreshPending = false;
     bool mIsOpaque = false;
     bool mContentDirty = false;
+    StretchEffect mStretchEffect = {};
 };
 
 std::string to_string(const LayerDebugInfo& info);
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 2f9a0c0..b273805 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -56,6 +56,7 @@
 #include <ui/Rect.h>
 #include <ui/Region.h>
 #include <ui/Rotation.h>
+#include <ui/StretchEffect.h>
 #include <ui/Transform.h>
 #include <utils/Errors.h>
 
@@ -135,6 +136,7 @@
         eFrameTimelineInfoChanged = 0x800'00000000,
         eBlurRegionsChanged = 0x1000'00000000,
         eAutoRefreshChanged = 0x2000'00000000,
+        eStretchChanged = 0x4000'00000000,
     };
 
     layer_state_t();
@@ -244,6 +246,9 @@
     // can and not wait for a frame to become available. This is only relevant
     // in shared buffer mode.
     bool autoRefresh;
+
+    // Stretch effect to be applied to this layer
+    StretchEffect stretchEffect;
 };
 
 struct ComposerState {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index b6b5c7c..5881221 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -189,6 +189,7 @@
 
     virtual status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
     virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
+    virtual status_t getExtraBufferCount(int* extraBuffers) const;
 
 protected:
     virtual ~Surface();
@@ -275,6 +276,7 @@
     int dispatchAddQueryInterceptor(va_list args);
     int dispatchGetLastQueuedBuffer(va_list args);
     int dispatchSetFrameTimelineInfo(va_list args);
+    int dispatchGetExtraBufferCount(va_list args);
     bool transformToDisplayInverse();
 
 protected:
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e7abfe6..6f0f18c 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -80,6 +80,10 @@
 using TransactionCompletedCallback =
         std::function<void(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/,
                            const std::vector<SurfaceControlStats>& /*stats*/)>;
+using SurfaceStatsCallback =
+        std::function<void(void* /*context*/, nsecs_t /*latchTime*/,
+                           const sp<Fence>& /*presentFence*/,
+                           const SurfaceStats& /*stats*/)>;
 
 // ---------------------------------------------------------------------------
 
@@ -108,44 +112,33 @@
     static status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*);
 
     // Get immutable information about given physical display.
-    static status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*);
+    static status_t getStaticDisplayInfo(const sp<IBinder>& display, ui::StaticDisplayInfo*);
 
-    // Get configurations supported by given physical display.
-    static status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>*);
+    // Get dynamic information about given physical display.
+    static status_t getDynamicDisplayInfo(const sp<IBinder>& display, ui::DynamicDisplayInfo*);
 
-    // Get the ID of the active DisplayConfig, as getDisplayConfigs index.
-    static int getActiveConfig(const sp<IBinder>& display);
-
-    // Shorthand for getDisplayConfigs element at getActiveConfig index.
-    static status_t getActiveDisplayConfig(const sp<IBinder>& display, DisplayConfig*);
+    // Shorthand for the active display mode from getDynamicDisplayInfo().
+    // TODO(b/180391891): Update clients to use getDynamicDisplayInfo and remove this function.
+    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, ui::DisplayModeId 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);
-
-    // Gets the list of supported color modes for the given display
-    static status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<ui::ColorMode>* outColorModes);
+    static status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+                                               ui::DisplayModeId* outDefaultMode,
+                                               bool* outAllowGroupSwitching,
+                                               float* outPrimaryRefreshRateMin,
+                                               float* outPrimaryRefreshRateMax,
+                                               float* outAppRequestRefreshRateMin,
+                                               float* outAppRequestRefreshRateMax);
 
     // Get the coordinates of the display's native color primaries
     static status_t getDisplayNativePrimaries(const sp<IBinder>& display,
             ui::DisplayPrimaries& outPrimaries);
 
-    // Gets the active color mode for the given display
-    static ui::ColorMode getActiveColorMode(const sp<IBinder>& display);
-
     // Sets the active color mode for the given display
     static status_t setActiveColorMode(const sp<IBinder>& display,
             ui::ColorMode colorMode);
@@ -551,6 +544,10 @@
         // transactions from blocking each other.
         Transaction& setApplyToken(const sp<IBinder>& token);
 
+        Transaction& setStretchEffect(const sp<SurfaceControl>& sc, float left, float top,
+                                      float right, float bottom, float vecX, float vecY,
+                                      float maxAmount);
+
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
 
@@ -580,9 +577,6 @@
     static status_t clearAnimationFrameStats();
     static status_t getAnimationFrameStats(FrameStats* outStats);
 
-    static status_t getHdrCapabilities(const sp<IBinder>& display,
-            HdrCapabilities* outCapabilities);
-
     static void setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation,
                                      const Rect& layerStackRect, const Rect& displayRect);
 
@@ -647,8 +641,21 @@
                 surfaceControls;
     };
 
+    struct SurfaceStatsCallbackEntry {
+        SurfaceStatsCallbackEntry(void* context, void* cookie, SurfaceStatsCallback callback)
+                : context(context),
+                cookie(cookie),
+                callback(callback) {}
+
+        void* context;
+        void* cookie;
+        SurfaceStatsCallback callback;
+    };
+
     std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
     std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);
+    std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry>
+                mSurfaceStatsListeners GUARDED_BY(mMutex);
 
 public:
     static sp<TransactionCompletedListener> getInstance();
@@ -676,6 +683,10 @@
      */
     void removeJankListener(const sp<JankDataListener>& listener);
 
+    void addSurfaceStatsListener(void* context, void* cookie, sp<SurfaceControl> surfaceControl,
+                SurfaceStatsCallback listener);
+    void removeSurfaceStatsListener(void* context, void* cookie);
+
     // Overrides BnTransactionCompletedListener's onTransactionCompleted
     void onTransactionCompleted(ListenerStats stats) override;
 };
diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp
index 64b1eac..bddb0ac 100644
--- a/libs/gui/sysprop/Android.bp
+++ b/libs/gui/sysprop/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 sysprop_library {
     name: "LibGuiProperties",
     srcs: ["*.sysprop"],
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 53c13c8..c801c62 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -2,6 +2,15 @@
 
 // Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
 // to integrate with auto-test framework.
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "libgui_test",
     test_suites: ["device-tests"],
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 70e656d..fb07a19 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();
 
@@ -129,7 +129,11 @@
     }
 
     void setUpProducer(BLASTBufferQueueHelper adapter, sp<IGraphicBufferProducer>& producer) {
-        auto igbProducer = adapter.getIGraphicBufferProducer();
+        producer = adapter.getIGraphicBufferProducer();
+        setUpProducer(producer);
+    }
+
+    void setUpProducer(sp<IGraphicBufferProducer>& igbProducer) {
         ASSERT_NE(nullptr, igbProducer.get());
         ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2));
         IGraphicBufferProducer::QueueBufferOutput qbOutput;
@@ -137,7 +141,6 @@
                   igbProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false,
                                        &qbOutput));
         ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
-        producer = igbProducer;
     }
 
     void fillBuffer(uint32_t* bufData, Rect rect, uint32_t stride, uint8_t r, uint8_t g,
@@ -555,6 +558,8 @@
     ASSERT_EQ(queuesToNativeWindow, 1);
 }
 
+// Test a slow producer doesn't hold up a faster producer from the same client. Essentially tests
+// BBQ uses separate transaction queues.
 TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) {
     sp<SurfaceControl> bgSurface =
             mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
@@ -781,7 +786,7 @@
     void setUpAndQueueBuffer(const sp<IGraphicBufferProducer>& igbProducer,
                              nsecs_t* requestedPresentTime, nsecs_t* postedTime,
                              IGraphicBufferProducer::QueueBufferOutput* qbOutput,
-                             bool getFrameTimestamps) {
+                             bool getFrameTimestamps, nsecs_t requestedPresentTimeDelay = 0) {
         int slot;
         sp<Fence> fence;
         sp<GraphicBuffer> buf;
@@ -791,7 +796,7 @@
         ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
         ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
 
-        nsecs_t requestedTime = systemTime();
+        nsecs_t requestedTime = systemTime() + requestedPresentTimeDelay;
         if (requestedPresentTime) *requestedPresentTime = requestedTime;
         IGraphicBufferProducer::QueueBufferInput input(requestedTime, false, HAL_DATASPACE_UNKNOWN,
                                                        Rect(mDisplayWidth, mDisplayHeight),
@@ -801,6 +806,27 @@
         if (postedTime) *postedTime = systemTime();
         igbProducer->queueBuffer(slot, input, qbOutput);
     }
+
+    void createBufferQueueProducer(sp<IGraphicBufferProducer>* bqIgbp) {
+        mBufferQueueSurfaceControl =
+                mClient->createSurface(String8("BqSurface"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+                                       ISurfaceComposerClient::eFXSurfaceBufferQueue);
+        ASSERT_NE(nullptr, mBufferQueueSurfaceControl.get());
+        Transaction()
+                .setLayerStack(mBufferQueueSurfaceControl, 0)
+                .show(mBufferQueueSurfaceControl)
+                .setDataspace(mBufferQueueSurfaceControl, ui::Dataspace::V0_SRGB)
+                .setSize(mBufferQueueSurfaceControl, mDisplayWidth, mDisplayHeight)
+                .setLayer(mBufferQueueSurfaceControl, std::numeric_limits<int32_t>::max())
+                .apply();
+
+        sp<Surface> bqSurface = mBufferQueueSurfaceControl->getSurface();
+        ASSERT_NE(nullptr, bqSurface.get());
+
+        *bqIgbp = bqSurface->getIGraphicBufferProducer();
+        setUpProducer(*bqIgbp);
+    }
+    sp<SurfaceControl> mBufferQueueSurfaceControl;
 };
 
 TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) {
@@ -853,4 +879,153 @@
     // wait for any callbacks that have not been received
     adapter.waitForCallbacks();
 }
+
+// Runs the same Frame Event History test
+TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic_BufferQueue) {
+    sp<IGraphicBufferProducer> bqIgbp;
+    createBufferQueueProducer(&bqIgbp);
+
+    ProducerFrameEventHistory history;
+    IGraphicBufferProducer::QueueBufferOutput qbOutput;
+    nsecs_t requestedPresentTimeA = 0;
+    nsecs_t postedTimeA = 0;
+    setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeA, &postedTimeA, &qbOutput, true);
+    history.applyDelta(qbOutput.frameTimestamps);
+
+    FrameEvents* events = nullptr;
+    events = history.getFrame(1);
+    ASSERT_NE(nullptr, events);
+    ASSERT_EQ(1, events->frameNumber);
+    ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+    ASSERT_GE(events->postedTime, postedTimeA);
+
+    // wait for buffer to be presented
+    std::this_thread::sleep_for(200ms);
+
+    nsecs_t requestedPresentTimeB = 0;
+    nsecs_t postedTimeB = 0;
+    setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
+    history.applyDelta(qbOutput.frameTimestamps);
+    events = history.getFrame(1);
+    ASSERT_NE(nullptr, events);
+
+    // frame number, requestedPresentTime, and postTime should not have changed
+    ASSERT_EQ(1, events->frameNumber);
+    ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+    ASSERT_GE(events->postedTime, postedTimeA);
+
+    ASSERT_GE(events->latchTime, postedTimeA);
+    ASSERT_FALSE(events->hasDequeueReadyInfo());
+
+    ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
+    ASSERT_NE(nullptr, events->displayPresentFence);
+    ASSERT_NE(nullptr, events->releaseFence);
+
+    // we should also have gotten the initial values for the next frame
+    events = history.getFrame(2);
+    ASSERT_NE(nullptr, events);
+    ASSERT_EQ(2, events->frameNumber);
+    ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
+    ASSERT_GE(events->postedTime, postedTimeB);
+}
+
+TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) {
+    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+    sp<IGraphicBufferProducer> igbProducer;
+    setUpProducer(adapter, igbProducer);
+
+    ProducerFrameEventHistory history;
+    IGraphicBufferProducer::QueueBufferOutput qbOutput;
+    nsecs_t requestedPresentTimeA = 0;
+    nsecs_t postedTimeA = 0;
+    nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+    setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true,
+                        presentTimeDelay);
+    history.applyDelta(qbOutput.frameTimestamps);
+
+    FrameEvents* events = nullptr;
+    events = history.getFrame(1);
+    ASSERT_NE(nullptr, events);
+    ASSERT_EQ(1, events->frameNumber);
+    ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+    ASSERT_GE(events->postedTime, postedTimeA);
+
+    // queue another buffer so the first can be dropped
+    nsecs_t requestedPresentTimeB = 0;
+    nsecs_t postedTimeB = 0;
+    setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
+    history.applyDelta(qbOutput.frameTimestamps);
+    events = history.getFrame(1);
+    ASSERT_NE(nullptr, events);
+
+    // frame number, requestedPresentTime, and postTime should not have changed
+    ASSERT_EQ(1, events->frameNumber);
+    ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+    ASSERT_GE(events->postedTime, postedTimeA);
+
+    // a valid latchtime should not be set
+    ASSERT_FALSE(events->hasLatchInfo());
+    ASSERT_FALSE(events->hasDequeueReadyInfo());
+
+    ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
+    ASSERT_NE(nullptr, events->displayPresentFence);
+    ASSERT_NE(nullptr, events->releaseFence);
+
+    // we should also have gotten the initial values for the next frame
+    events = history.getFrame(2);
+    ASSERT_NE(nullptr, events);
+    ASSERT_EQ(2, events->frameNumber);
+    ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
+    ASSERT_GE(events->postedTime, postedTimeB);
+}
+
+TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame_BufferQueue) {
+    sp<IGraphicBufferProducer> bqIgbp;
+    createBufferQueueProducer(&bqIgbp);
+
+    ProducerFrameEventHistory history;
+    IGraphicBufferProducer::QueueBufferOutput qbOutput;
+    nsecs_t requestedPresentTimeA = 0;
+    nsecs_t postedTimeA = 0;
+    nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+    setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeA, &postedTimeA, &qbOutput, true,
+                        presentTimeDelay);
+    history.applyDelta(qbOutput.frameTimestamps);
+
+    FrameEvents* events = nullptr;
+    events = history.getFrame(1);
+    ASSERT_NE(nullptr, events);
+    ASSERT_EQ(1, events->frameNumber);
+    ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+    ASSERT_GE(events->postedTime, postedTimeA);
+
+    // queue another buffer so the first can be dropped
+    nsecs_t requestedPresentTimeB = 0;
+    nsecs_t postedTimeB = 0;
+    setUpAndQueueBuffer(bqIgbp, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
+    history.applyDelta(qbOutput.frameTimestamps);
+    events = history.getFrame(1);
+    ASSERT_NE(nullptr, events);
+
+    // frame number, requestedPresentTime, and postTime should not have changed
+    ASSERT_EQ(1, events->frameNumber);
+    ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+    ASSERT_GE(events->postedTime, postedTimeA);
+
+    // a valid latchtime should not be set
+    ASSERT_FALSE(events->hasLatchInfo());
+    ASSERT_FALSE(events->hasDequeueReadyInfo());
+
+    ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
+    ASSERT_NE(nullptr, events->displayPresentFence);
+    ASSERT_NE(nullptr, events->releaseFence);
+
+    // we should also have gotten the initial values for the next frame
+    events = history.getFrame(2);
+    ASSERT_NE(nullptr, events);
+    ASSERT_EQ(2, events->frameNumber);
+    ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
+    ASSERT_GE(events->postedTime, postedTimeB);
+}
+
 } // namespace android
diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp
index c5093e2..7dbba31 100644
--- a/libs/gui/tests/DisplayEventStructLayout_test.cpp
+++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp
@@ -25,7 +25,7 @@
 TEST(DisplayEventStructLayoutTest, TestEventAlignment) {
     CHECK_OFFSET(DisplayEventReceiver::Event, vsync, 24);
     CHECK_OFFSET(DisplayEventReceiver::Event, hotplug, 24);
-    CHECK_OFFSET(DisplayEventReceiver::Event, config, 24);
+    CHECK_OFFSET(DisplayEventReceiver::Event, modeChange, 24);
 
     CHECK_OFFSET(DisplayEventReceiver::Event::Header, type, 0);
     CHECK_OFFSET(DisplayEventReceiver::Event::Header, displayId, 8);
@@ -38,8 +38,8 @@
 
     CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0);
 
-    CHECK_OFFSET(DisplayEventReceiver::Event::Config, configId, 0);
-    CHECK_OFFSET(DisplayEventReceiver::Event::Config, vsyncPeriod, 8);
+    CHECK_OFFSET(DisplayEventReceiver::Event::ModeChange, modeId, 0);
+    CHECK_OFFSET(DisplayEventReceiver::Event::ModeChange, vsyncPeriod, 8);
 
     CHECK_OFFSET(DisplayEventReceiver::Event::FrameRateOverride, uid, 0);
     CHECK_OFFSET(DisplayEventReceiver::Event::FrameRateOverride, frameRateHz, 8);
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 31cbbdc..d65a40b 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -41,7 +41,7 @@
 #include <input/InputTransport.h>
 #include <input/InputWindow.h>
 
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
@@ -272,13 +272,13 @@
         const auto display = mComposerClient->getInternalDisplayToken();
         ASSERT_NE(display, nullptr);
 
-        DisplayConfig config;
-        ASSERT_EQ(NO_ERROR, mComposerClient->getActiveDisplayConfig(display, &config));
+        ui::DisplayMode mode;
+        ASSERT_EQ(NO_ERROR, mComposerClient->getActiveDisplayMode(display, &mode));
 
         // After a new buffer is queued, SurfaceFlinger is notified and will
         // latch the new buffer on next vsync.  Let's heuristically wait for 3
         // vsyncs.
-        mBufferPostDelay = static_cast<int32_t>(1e6 / config.refreshRate) * 3;
+        mBufferPostDelay = static_cast<int32_t>(1e6 / mode.refreshRate) * 3;
     }
 
     void TearDown() {
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 3f7a5b1..3397198 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -32,6 +32,7 @@
 #include <inttypes.h>
 #include <private/gui/ComposerService.h>
 #include <ui/BufferQueueDefs.h>
+#include <ui/DisplayMode.h>
 #include <ui/Rect.h>
 #include <utils/String8.h>
 
@@ -734,10 +735,11 @@
     }
 
     void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
-    status_t getDisplayInfo(const sp<IBinder>& /*display*/, DisplayInfo*) override {
+    status_t getStaticDisplayInfo(const sp<IBinder>& /*display*/, ui::StaticDisplayInfo*) override {
         return NO_ERROR;
     }
-    status_t getDisplayConfigs(const sp<IBinder>& /*display*/, Vector<DisplayConfig>*) override {
+    status_t getDynamicDisplayInfo(const sp<IBinder>& /*display*/,
+                                   ui::DynamicDisplayInfo*) override {
         return NO_ERROR;
     }
     status_t getDisplayState(const sp<IBinder>& /*display*/, ui::DisplayState*) override {
@@ -745,19 +747,10 @@
     }
     status_t getDisplayStats(const sp<IBinder>& /*display*/,
             DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
-    int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
-    status_t getDisplayColorModes(const sp<IBinder>& /*display*/,
-            Vector<ColorMode>* /*outColorModes*/) override {
-        return NO_ERROR;
-    }
     status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
             ui::DisplayPrimaries& /*primaries*/) override {
         return NO_ERROR;
     }
-    ColorMode getActiveColorMode(const sp<IBinder>& /*display*/)
-            override {
-        return ColorMode::NATIVE;
-    }
     status_t setActiveColorMode(const sp<IBinder>& /*display*/,
         ColorMode /*colorMode*/) override { return NO_ERROR; }
     status_t captureDisplay(const DisplayCaptureArgs& /* captureArgs */,
@@ -787,10 +780,6 @@
     status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
         return NO_ERROR;
     }
-    status_t getHdrCapabilities(const sp<IBinder>& /*display*/,
-            HdrCapabilities* /*outCapabilities*/) const override {
-        return NO_ERROR;
-    }
     status_t enableVSyncInjections(bool /*enable*/) override {
         return NO_ERROR;
     }
@@ -843,21 +832,22 @@
             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*/,
+                                        ui::DisplayModeId /*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*/,
+                                        ui::DisplayModeId* /*outDefaultMode*/,
+                                        bool* /*outAllowGroupSwitching*/,
+                                        float* /*outPrimaryRefreshRateMin*/,
+                                        float* /*outPrimaryRefreshRateMax*/,
+                                        float* /*outAppRequestRefreshRateMin*/,
+                                        float* /*outAppRequestRefreshRateMax*/) override {
         return NO_ERROR;
     };
     status_t notifyPowerBoost(int32_t /*boostId*/) override { return NO_ERROR; }
@@ -889,6 +879,8 @@
 
     int getGPUContextPriority() override { return 0; };
 
+    status_t getExtraBufferCount(int* /*extraBuffers*/) const override { return NO_ERROR; }
+
 protected:
     IBinder* onAsBinder() override { return nullptr; }
 
diff --git a/libs/incidentcompanion/Android.bp b/libs/incidentcompanion/Android.bp
index 63411b9..ef7f523 100644
--- a/libs/incidentcompanion/Android.bp
+++ b/libs/incidentcompanion/Android.bp
@@ -14,6 +14,15 @@
  * limitations under the License.
  */
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 filegroup {
     name: "incidentcompanion_aidl",
     srcs: [
@@ -49,4 +58,3 @@
         "-Wunused-parameter",
     ],
 }
-
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index fce3000..4253610 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -14,6 +14,15 @@
 
 // libinput is partially built for the host (used by build time keymap validation tool)
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 filegroup {
     name: "inputconstants_aidl",
     srcs: [
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index acea473..6218fdc 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -234,6 +234,7 @@
         }
         case InputMessage::Type::FINISHED: {
             msg->body.finished.handled = body.finished.handled;
+            msg->body.finished.consumeTime = body.finished.consumeTime;
             break;
         }
         case InputMessage::Type::FOCUS: {
@@ -597,7 +598,8 @@
     return mChannel->sendMessage(&msg);
 }
 
-status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
+status_t InputPublisher::receiveFinishedSignal(
+        const std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)>& callback) {
     if (DEBUG_TRANSPORT_ACTIONS) {
         ALOGD("channel '%s' publisher ~ receiveFinishedSignal", mChannel->getName().c_str());
     }
@@ -605,8 +607,6 @@
     InputMessage msg;
     status_t result = mChannel->receiveMessage(&msg);
     if (result) {
-        *outSeq = 0;
-        *outHandled = false;
         return result;
     }
     if (msg.header.type != InputMessage::Type::FINISHED) {
@@ -614,8 +614,7 @@
                 mChannel->getName().c_str(), msg.header.type);
         return UNKNOWN_ERROR;
     }
-    *outSeq = msg.header.seq;
-    *outHandled = msg.body.finished.handled == 1;
+    callback(msg.header.seq, msg.body.finished.handled == 1, msg.body.finished.consumeTime);
     return OK;
 }
 
@@ -651,6 +650,9 @@
         } else {
             // Receive a fresh message.
             status_t result = mChannel->receiveMessage(&mMsg);
+            if (result == OK) {
+                mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
+            }
             if (result) {
                 // Consume the next batched event unless batches are being held for later.
                 if (consumeBatches || result != WOULD_BLOCK) {
@@ -1147,12 +1149,33 @@
     return sendUnchainedFinishedSignal(seq, handled);
 }
 
+nsecs_t InputConsumer::getConsumeTime(uint32_t seq) const {
+    auto it = mConsumeTimes.find(seq);
+    // Consume time will be missing if either 'finishInputEvent' is called twice, or if it was
+    // called for the wrong (synthetic?) input event. Either way, it is a bug that should be fixed.
+    LOG_ALWAYS_FATAL_IF(it == mConsumeTimes.end(), "Could not find consume time for seq=%" PRIu32,
+                        seq);
+    return it->second;
+}
+
+void InputConsumer::popConsumeTime(uint32_t seq) {
+    mConsumeTimes.erase(seq);
+}
+
 status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
     InputMessage msg;
     msg.header.type = InputMessage::Type::FINISHED;
     msg.header.seq = seq;
     msg.body.finished.handled = handled ? 1 : 0;
-    return mChannel->sendMessage(&msg);
+    msg.body.finished.consumeTime = getConsumeTime(seq);
+    status_t result = mChannel->sendMessage(&msg);
+    if (result == OK) {
+        // Remove the consume time if the socket write succeeded. We will not need to ack this
+        // message anymore. If the socket write did not succeed, we will try again and will still
+        // need consume time.
+        popConsumeTime(seq);
+    }
+    return result;
 }
 
 bool InputConsumer::hasDeferredEvent() const {
@@ -1304,8 +1327,9 @@
                     break;
                 }
                 case InputMessage::Type::FINISHED: {
-                    out += android::base::StringPrintf("handled=%s",
-                                                       toString(msg.body.finished.handled));
+                    out += android::base::StringPrintf("handled=%s, consumeTime=%" PRId64,
+                                                       toString(msg.body.finished.handled),
+                                                       msg.body.finished.consumeTime);
                     break;
                 }
                 case InputMessage::Type::FOCUS: {
@@ -1335,6 +1359,14 @@
     if (mSeqChains.empty()) {
         out += "    <empty>\n";
     }
+    out += "mConsumeTimes:\n";
+    for (const auto& [seq, consumeTime] : mConsumeTimes) {
+        out += android::base::StringPrintf("    seq = %" PRIu32 " consumeTime = %" PRId64, seq,
+                                           consumeTime);
+    }
+    if (mConsumeTimes.empty()) {
+        out += "    <empty>\n";
+    }
     return out;
 }
 
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index b23aade..fe8a567 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -1,4 +1,13 @@
 // Build the unit tests.
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "libinput_tests",
     srcs: [
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 9da7b69..e7e566d 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -82,6 +82,7 @@
     constexpr int32_t repeatCount = 1;
     constexpr nsecs_t downTime = 3;
     constexpr nsecs_t eventTime = 4;
+    const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     status = mPublisher->publishKeyEvent(seq, eventId, deviceId, source, displayId, hmac, action,
                                          flags, keyCode, scanCode, metaState, repeatCount, downTime,
@@ -122,13 +123,22 @@
 
     uint32_t finishedSeq = 0;
     bool handled = false;
-    status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+    nsecs_t consumeTime;
+    status = mPublisher->receiveFinishedSignal(
+            [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
+                                                   nsecs_t inConsumeTime) -> void {
+                finishedSeq = inSeq;
+                handled = inHandled;
+                consumeTime = inConsumeTime;
+            });
     ASSERT_EQ(OK, status)
             << "publisher receiveFinishedSignal should return OK";
     ASSERT_EQ(seq, finishedSeq)
             << "publisher receiveFinishedSignal should have returned the original sequence number";
     ASSERT_TRUE(handled)
             << "publisher receiveFinishedSignal should have set handled to consumer's reply";
+    ASSERT_GE(consumeTime, publishTime)
+            << "finished signal's consume time should be greater than publish time";
 }
 
 void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
@@ -160,6 +170,7 @@
     constexpr nsecs_t downTime = 3;
     constexpr size_t pointerCount = 3;
     constexpr nsecs_t eventTime = 4;
+    const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
     for (size_t i = 0; i < pointerCount; i++) {
@@ -262,13 +273,22 @@
 
     uint32_t finishedSeq = 0;
     bool handled = true;
-    status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+    nsecs_t consumeTime;
+    status = mPublisher->receiveFinishedSignal(
+            [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
+                                                   nsecs_t inConsumeTime) -> void {
+                finishedSeq = inSeq;
+                handled = inHandled;
+                consumeTime = inConsumeTime;
+            });
     ASSERT_EQ(OK, status)
             << "publisher receiveFinishedSignal should return OK";
     ASSERT_EQ(seq, finishedSeq)
             << "publisher receiveFinishedSignal should have returned the original sequence number";
     ASSERT_FALSE(handled)
             << "publisher receiveFinishedSignal should have set handled to consumer's reply";
+    ASSERT_GE(consumeTime, publishTime)
+            << "finished signal's consume time should be greater than publish time";
 }
 
 void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() {
@@ -278,6 +298,7 @@
     int32_t eventId = InputEvent::nextId();
     constexpr bool hasFocus = true;
     constexpr bool inTouchMode = true;
+    const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     status = mPublisher->publishFocusEvent(seq, eventId, hasFocus, inTouchMode);
     ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK";
@@ -302,12 +323,21 @@
 
     uint32_t finishedSeq = 0;
     bool handled = false;
-    status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+    nsecs_t consumeTime;
+    status = mPublisher->receiveFinishedSignal(
+            [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
+                                                   nsecs_t inConsumeTime) -> void {
+                finishedSeq = inSeq;
+                handled = inHandled;
+                consumeTime = inConsumeTime;
+            });
     ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK";
     ASSERT_EQ(seq, finishedSeq)
             << "publisher receiveFinishedSignal should have returned the original sequence number";
     ASSERT_TRUE(handled)
             << "publisher receiveFinishedSignal should have set handled to consumer's reply";
+    ASSERT_GE(consumeTime, publishTime)
+            << "finished signal's consume time should be greater than publish time";
 }
 
 void InputPublisherAndConsumerTest::PublishAndConsumeCaptureEvent() {
@@ -316,6 +346,7 @@
     constexpr uint32_t seq = 42;
     int32_t eventId = InputEvent::nextId();
     constexpr bool captureEnabled = true;
+    const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     status = mPublisher->publishCaptureEvent(seq, eventId, captureEnabled);
     ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK";
@@ -339,12 +370,21 @@
 
     uint32_t finishedSeq = 0;
     bool handled = false;
-    status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+    nsecs_t consumeTime;
+    status = mPublisher->receiveFinishedSignal(
+            [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
+                                                   nsecs_t inConsumeTime) -> void {
+                finishedSeq = inSeq;
+                handled = inHandled;
+                consumeTime = inConsumeTime;
+            });
     ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK";
     ASSERT_EQ(seq, finishedSeq)
             << "publisher receiveFinishedSignal should have returned the original sequence number";
     ASSERT_TRUE(handled)
             << "publisher receiveFinishedSignal should have set handled to consumer's reply";
+    ASSERT_GE(consumeTime, publishTime)
+            << "finished signal's consume time should be greater than publish time";
 }
 
 TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 4107d61..a886585 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -83,6 +83,7 @@
   CHECK_OFFSET(InputMessage::Body::Capture, pointerCaptureEnabled, 4);
 
   CHECK_OFFSET(InputMessage::Body::Finished, handled, 4);
+  CHECK_OFFSET(InputMessage::Body::Finished, consumeTime, 8);
 }
 
 void TestHeaderSize() {
@@ -100,7 +101,7 @@
     static_assert(sizeof(InputMessage::Body::Motion) ==
                   offsetof(InputMessage::Body::Motion, pointers) +
                           sizeof(InputMessage::Body::Motion::Pointer) * MAX_POINTERS);
-    static_assert(sizeof(InputMessage::Body::Finished) == 8);
+    static_assert(sizeof(InputMessage::Body::Finished) == 16);
     static_assert(sizeof(InputMessage::Body::Focus) == 8);
     static_assert(sizeof(InputMessage::Body::Capture) == 8);
 }
diff --git a/libs/math/Android.bp b/libs/math/Android.bp
index 22d4712..3cf9f3f 100644
--- a/libs/math/Android.bp
+++ b/libs/math/Android.bp
@@ -12,6 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["frameworks_native_libs_math_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_libs_math_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_library_static {
     name: "libmath",
     host_supported: true,
diff --git a/libs/math/tests/Android.bp b/libs/math/tests/Android.bp
index 0184f56..4a7c4dd 100644
--- a/libs/math/tests/Android.bp
+++ b/libs/math/tests/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_libs_math_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_libs_math_license"],
+}
+
 cc_test {
     name: "vec_test",
     srcs: ["vec_test.cpp"],
diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp
index 8399e8c..1a4729c 100644
--- a/libs/nativebase/Android.bp
+++ b/libs/nativebase/Android.bp
@@ -12,6 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["frameworks_native_libs_nativebase_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_libs_nativebase_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_library_headers {
     name: "libnativebase_headers",
     vendor_available: true,
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..6288194 100644
--- a/libs/nativedisplay/ADisplay.cpp
+++ b/libs/nativedisplay/ADisplay.cpp
@@ -16,10 +16,11 @@
 
 #include <apex/display.h>
 #include <gui/SurfaceComposerClient.h>
-#include <ui/DisplayConfig.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayMode.h>
+#include <ui/DynamicDisplayInfo.h>
 #include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
+#include <ui/StaticDisplayInfo.h>
 
 #include <algorithm>
 #include <optional>
@@ -33,6 +34,11 @@
  */
 struct DisplayConfigImpl {
     /**
+     * The ID of the display configuration.
+     */
+    size_t id;
+
+    /**
      * The width in pixels of the display configuration.
      */
     int32_t width{0};
@@ -134,34 +140,36 @@
         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]);
 
-        DisplayInfo info;
-        if (const status_t status = SurfaceComposerClient::getDisplayInfo(token, &info);
+        ui::StaticDisplayInfo staticInfo;
+        if (const status_t status = SurfaceComposerClient::getStaticDisplayInfo(token, &staticInfo);
             status != OK) {
             return status;
         }
 
-        Vector<DisplayConfig> configs;
-        if (const status_t status = SurfaceComposerClient::getDisplayConfigs(token, &configs);
+        ui::DynamicDisplayInfo dynamicInfo;
+        if (const status_t status =
+                    SurfaceComposerClient::getDynamicDisplayInfo(token, &dynamicInfo);
             status != OK) {
             return status;
         }
-        if (configs.empty()) {
+        const auto& modes = dynamicInfo.supportedDisplayModes;
+        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{static_cast<size_t>(mode.id), mode.resolution.getWidth(),
+                                      mode.resolution.getHeight(), staticInfo.density,
+                                      mode.refreshRate, mode.sfVsyncOffset, mode.appVsyncOffset});
         }
     }
 
@@ -192,7 +200,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 +208,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,15 +265,22 @@
     CHECK_NOT_NULL(display);
 
     sp<IBinder> token = getToken(display);
-    const int index = SurfaceComposerClient::getActiveConfig(token);
-    if (index < 0) {
-        return index;
+    ui::DynamicDisplayInfo info;
+    if (const auto status = SurfaceComposerClient::getDynamicDisplayInfo(token, &info);
+        status != OK) {
+        return status;
     }
 
     DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display);
+    for (size_t i = 0; i < impl->numConfigs; i++) {
+        auto* config = impl->configs + i;
+        if (config->id == info.activeDisplayModeId) {
+            *outConfig = reinterpret_cast<ADisplayConfig*>(config);
+            return OK;
+        }
+    }
 
-    *outConfig = reinterpret_cast<ADisplayConfig*>(impl->configs + index);
-    return OK;
+    return NAME_NOT_FOUND;
 }
 
 float ADisplayConfig_getDensity(ADisplayConfig* config) {
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index 6574ae6..ed728dc 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -12,6 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: [
+        "frameworks_native_libs_nativedisplay_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_libs_nativedisplay_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_library_headers {
     name: "libnativedisplay_headers",
     export_include_dirs: ["include",],
diff --git a/libs/nativedisplay/include/apex/display.h b/libs/nativedisplay/include/apex/display.h
index a7eaf87..bd94b55 100644
--- a/libs/nativedisplay/include/apex/display.h
+++ b/libs/nativedisplay/include/apex/display.h
@@ -97,6 +97,11 @@
  * such an update is observed, then this method should be recalled to get the
  * new current configuration.
  *
+ * After a subsequent hotplug "connected" event the supported display configs
+ * may change. Then the preloaded display configs will be stale and the
+ * call for current config may return NAME_NOT_FOUND. In this case the client
+ * should release and re-acquire the display handle.
+ *
  * Returns OK on success, -errno on failure.
  */
 int ADisplay_getCurrentConfig(ADisplay* display, ADisplayConfig** outConfig);
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 3011dcc..8675439 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -12,6 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: [
+        "frameworks_native_libs_nativewindow_license",
+    ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_libs_nativewindow_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 ndk_headers {
     name: "libnativewindow_ndk_headers",
     from: "include/android",
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index ffe4412..7aa2cf4 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -256,6 +256,7 @@
     NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER          = 46,    /* private */
     NATIVE_WINDOW_SET_QUERY_INTERCEPTOR           = 47,    /* private */
     NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO         = 48,    /* private */
+    NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT          = 49,    /* private */
     // clang-format on
 };
 
@@ -1030,6 +1031,11 @@
                            frameTimelineVsyncId, inputEventId);
 }
 
+static inline int native_window_get_extra_buffer_count(
+    struct ANativeWindow* window, int* extraBuffers) {
+    return window->perform(window, NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT, extraBuffers);
+}
+
 // ------------------------------------------------------------------------------------------------
 // Candidates for APEX visibility
 // These functions are planned to be made stable for APEX modules, but have not
diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp
index 2e4bd99..30737c1 100644
--- a/libs/nativewindow/tests/Android.bp
+++ b/libs/nativewindow/tests/Android.bp
@@ -14,6 +14,17 @@
 // limitations under the License.
 //
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_libs_nativewindow_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: [
+        "frameworks_native_libs_nativewindow_license",
+    ],
+}
+
 cc_test {
     name: "libnativewindow_test",
     test_suites: [
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index d69c7ae..eb3b434 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "renderengine_defaults",
     cflags: [
@@ -31,10 +40,6 @@
         "libui",
         "libutils",
     ],
-    include_dirs: [
-        "external/skia/src/gpu",
-    ],
-    whole_static_libs: ["libskia"],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
 }
@@ -106,6 +111,10 @@
         ":librenderengine_threaded_sources",
         ":librenderengine_skia_sources",
     ],
+    include_dirs: [
+        "external/skia/src/gpu",
+    ],
+    whole_static_libs: ["libskia"],
     lto: {
         thin: true,
     },
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index 08cf2de..c478506 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -1,3 +1,5 @@
 alecmouri@google.com
+djsollen@google.com
 jreck@google.com
 lpy@google.com
+scroggo@google.com
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 64d6c6b..7496b74 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -72,6 +72,7 @@
                         base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
     bool cleanupPostRender(CleanupMode mode) override;
     int getContextPriority() override;
+    bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
 
     EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
     // Creates an output image for rendering to
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
index 19f18c0..3455e08 100644
--- a/libs/renderengine/gl/filters/BlurFilter.cpp
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -207,7 +207,7 @@
 }
 
 string BlurFilter::getVertexShader() const {
-    return R"SHADER(#version 310 es
+    return R"SHADER(#version 300 es
         precision mediump float;
 
         in vec2 aPosition;
@@ -222,7 +222,7 @@
 }
 
 string BlurFilter::getFragmentShader() const {
-    return R"SHADER(#version 310 es
+    return R"SHADER(#version 300 es
         precision mediump float;
 
         uniform sampler2D uTexture;
@@ -244,7 +244,7 @@
 }
 
 string BlurFilter::getMixFragShader() const {
-    string shader = R"SHADER(#version 310 es
+    string shader = R"SHADER(#version 300 es
         precision mediump float;
 
         in highp vec2 vUV;
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 3a727c9..7661233 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -28,6 +28,7 @@
 #include <ui/GraphicTypes.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
+#include <ui/StretchEffect.h>
 #include <ui/Transform.h>
 
 namespace android {
@@ -155,6 +156,8 @@
 
     std::vector<BlurRegion> blurRegions;
 
+    StretchEffect stretchEffect;
+
     // Name associated with the layer for debugging purposes.
     std::string name;
 };
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 506f81e..163a163 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -188,6 +188,10 @@
     // number of contexts that can be created at a specific priority level in the system.
     virtual int getContextPriority() = 0;
 
+    // Returns true if blur was requested in the RenderEngineCreationArgs and the implementation
+    // also supports background blur.  If false, no blur will be applied when drawing layers.
+    virtual bool supportsBackgroundBlur() = 0;
+
 protected:
     friend class threaded::RenderEngineThreaded;
 };
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 2c34da4..895ba3f 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -54,6 +54,7 @@
                           base::unique_fd*));
     MOCK_METHOD0(cleanFramebufferCache, void());
     MOCK_METHOD0(getContextPriority, int());
+    MOCK_METHOD0(supportsBackgroundBlur, bool());
 };
 
 } // namespace mock
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index dd26b17..327b04c 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -286,6 +286,7 @@
     }
 
     if (args.supportsBackgroundBlur) {
+        ALOGD("Background Blurs Enabled");
         mBlurFilter = new BlurFilter();
     }
     mCapture = std::make_unique<SkiaCapture>();
@@ -336,7 +337,7 @@
     if (useProtectedContext == mInProtectedContext) {
         return true;
     }
-    if (useProtectedContext && supportsProtectedContent()) {
+    if (useProtectedContext && !supportsProtectedContent()) {
         return false;
     }
     const EGLSurface surface =
@@ -491,6 +492,9 @@
                                                               const LayerSettings* layer,
                                                               const DisplaySettings& display,
                                                               bool undoPremultipliedAlpha) {
+    if (layer->stretchEffect.hasEffect()) {
+        // TODO: Implement
+    }
     if (mUseColorManagement &&
         needsLinearEffect(layer->colorTransform, layer->sourceDataspace, display.outputDataspace)) {
         LinearEffect effect = LinearEffect{.inputDataspace = layer->sourceDataspace,
@@ -513,6 +517,45 @@
     return shader;
 }
 
+void SkiaGLRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
+    if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+        // Record display settings when capture is running.
+        std::stringstream displaySettings;
+        PrintTo(display, &displaySettings);
+        // Store the DisplaySettings in additional information.
+        canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
+                               SkData::MakeWithCString(displaySettings.str().c_str()));
+    }
+
+    // Before doing any drawing, let's make sure that we'll start at the origin of the display.
+    // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
+    // displays might have different scaling when compared to the physical screen.
+
+    canvas->clipRect(getSkRect(display.physicalDisplay));
+    canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
+
+    const auto clipWidth = display.clip.width();
+    const auto clipHeight = display.clip.height();
+    auto rotatedClipWidth = clipWidth;
+    auto rotatedClipHeight = clipHeight;
+    // Scale is contingent on the rotation result.
+    if (display.orientation & ui::Transform::ROT_90) {
+        std::swap(rotatedClipWidth, rotatedClipHeight);
+    }
+    const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
+            static_cast<SkScalar>(rotatedClipWidth);
+    const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
+            static_cast<SkScalar>(rotatedClipHeight);
+    canvas->scale(scaleX, scaleY);
+
+    // Canvas rotation is done by centering the clip window at the origin, rotating, translating
+    // back so that the top left corner of the clip is at (0, 0).
+    canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
+    canvas->rotate(toDegrees(display.orientation));
+    canvas->translate(-clipWidth / 2, -clipHeight / 2);
+    canvas->translate(-display.clip.left, -display.clip.top);
+}
+
 status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
                                         const std::vector<const LayerSettings*>& layers,
                                         const sp<GraphicBuffer>& buffer,
@@ -567,57 +610,50 @@
         }
     }
 
-    sk_sp<SkSurface> surface =
+    sk_sp<SkSurface> dstSurface =
             surfaceTextureRef->getTexture()->getOrCreateSurface(mUseColorManagement
                                                                         ? display.outputDataspace
                                                                         : ui::Dataspace::UNKNOWN,
                                                                 grContext.get());
 
-    SkCanvas* canvas = mCapture->tryCapture(surface.get());
-    if (canvas == nullptr) {
+    SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
+    if (dstCanvas == nullptr) {
         ALOGE("Cannot acquire canvas from Skia.");
         return BAD_VALUE;
     }
+
+    // Find if any layers have requested blur, we'll use that info to decide when to render to an
+    // offscreen buffer and when to render to the native buffer.
+    sk_sp<SkSurface> activeSurface(dstSurface);
+    SkCanvas* canvas = dstCanvas;
+    SkiaCapture::OffscreenState offscreenCaptureState;
+    const LayerSettings* blurCompositionLayer = nullptr;
+    if (mBlurFilter) {
+        bool requiresCompositionLayer = false;
+        for (const auto& layer : layers) {
+            if (layer->backgroundBlurRadius > 0) {
+                // when skbug.com/11208 and b/176903027 are resolved we can add the additional
+                // restriction for layer->backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius
+                requiresCompositionLayer = true;
+            }
+            for (auto region : layer->blurRegions) {
+                if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) {
+                    requiresCompositionLayer = true;
+                }
+            }
+            if (requiresCompositionLayer) {
+                activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
+                canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
+                blurCompositionLayer = layer;
+                break;
+            }
+        }
+    }
+
+    canvas->save();
     // Clear the entire canvas with a transparent black to prevent ghost images.
     canvas->clear(SK_ColorTRANSPARENT);
-    canvas->save();
-
-    if (mCapture->isCaptureRunning()) {
-        // Record display settings when capture is running.
-        std::stringstream displaySettings;
-        PrintTo(display, &displaySettings);
-        // Store the DisplaySettings in additional information.
-        canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
-                               SkData::MakeWithCString(displaySettings.str().c_str()));
-    }
-
-    // Before doing any drawing, let's make sure that we'll start at the origin of the display.
-    // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
-    // displays might have different scaling when compared to the physical screen.
-
-    canvas->clipRect(getSkRect(display.physicalDisplay));
-    canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
-
-    const auto clipWidth = display.clip.width();
-    const auto clipHeight = display.clip.height();
-    auto rotatedClipWidth = clipWidth;
-    auto rotatedClipHeight = clipHeight;
-    // Scale is contingent on the rotation result.
-    if (display.orientation & ui::Transform::ROT_90) {
-        std::swap(rotatedClipWidth, rotatedClipHeight);
-    }
-    const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
-            static_cast<SkScalar>(rotatedClipWidth);
-    const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
-            static_cast<SkScalar>(rotatedClipHeight);
-    canvas->scale(scaleX, scaleY);
-
-    // Canvas rotation is done by centering the clip window at the origin, rotating, translating
-    // back so that the top left corner of the clip is at (0, 0).
-    canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
-    canvas->rotate(toDegrees(display.orientation));
-    canvas->translate(-clipWidth / 2, -clipHeight / 2);
-    canvas->translate(-display.clip.left, -display.clip.top);
+    initCanvas(canvas, display);
 
     // TODO: clearRegion was required for SurfaceView when a buffer is not yet available but the
     // view is still on-screen. The clear region could be re-specified as a black color layer,
@@ -644,9 +680,45 @@
 
     for (const auto& layer : layers) {
         ATRACE_NAME("DrawLayer");
-        canvas->save();
 
-        if (mCapture->isCaptureRunning()) {
+        sk_sp<SkImage> blurInput;
+        if (blurCompositionLayer == layer) {
+            LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface);
+            LOG_ALWAYS_FATAL_IF(canvas == dstCanvas);
+
+            // save a snapshot of the activeSurface to use as input to the blur shaders
+            blurInput = activeSurface->makeImageSnapshot();
+
+            // TODO we could skip this step if we know the blur will cover the entire image
+            //  blit the offscreen framebuffer into the destination AHB
+            SkPaint paint;
+            paint.setBlendMode(SkBlendMode::kSrc);
+            if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+                uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
+                dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
+                                          String8::format("SurfaceID|%" PRId64, id).c_str(),
+                                          nullptr);
+                dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
+            } else {
+                activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
+            }
+
+            // assign dstCanvas to canvas and ensure that the canvas state is up to date
+            canvas = dstCanvas;
+            canvas->save();
+            initCanvas(canvas, display);
+
+            LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getSaveCount() !=
+                                dstSurface->getCanvas()->getSaveCount());
+            LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getTotalMatrix() !=
+                                dstSurface->getCanvas()->getTotalMatrix());
+
+            // assign dstSurface to activeSurface
+            activeSurface = dstSurface;
+        }
+
+        canvas->save();
+        if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
             // Record the name of the layer if the capture is running.
             std::stringstream layerSettings;
             PrintTo(*layer, &layerSettings);
@@ -654,34 +726,42 @@
             canvas->drawAnnotation(SkRect::MakeEmpty(), layer->name.c_str(),
                                    SkData::MakeWithCString(layerSettings.str().c_str()));
         }
-
         // Layers have a local transform that should be applied to them
         canvas->concat(getSkM44(layer->geometry.positionTransform).asM33());
 
-        SkPaint paint;
-        const auto& bounds = layer->geometry.boundaries;
-        const auto dest = getSkRect(bounds);
-        const auto layerRect = canvas->getTotalMatrix().mapRect(dest);
-        std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
-        if (mBlurFilter) {
+        const auto bounds = getSkRect(layer->geometry.boundaries);
+        if (mBlurFilter && layerHasBlur(layer)) {
+            std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
+
+            // if multiple layers have blur, then we need to take a snapshot now because
+            // only the lowest layer will have blurImage populated earlier
+            if (!blurInput) {
+                blurInput = activeSurface->makeImageSnapshot();
+            }
+            // rect to be blurred in the coordinate space of blurInput
+            const auto blurRect = canvas->getTotalMatrix().mapRect(bounds);
+
             if (layer->backgroundBlurRadius > 0) {
                 ATRACE_NAME("BackgroundBlur");
-                auto blurredSurface = mBlurFilter->generate(canvas, surface,
-                                                            layer->backgroundBlurRadius, layerRect);
-                cachedBlurs[layer->backgroundBlurRadius] = blurredSurface;
+                auto blurredImage =
+                        mBlurFilter->generate(grContext.get(), layer->backgroundBlurRadius,
+                                              blurInput, blurRect);
 
-                drawBlurRegion(canvas, getBlurRegion(layer), layerRect, blurredSurface);
+                cachedBlurs[layer->backgroundBlurRadius] = blurredImage;
+
+                mBlurFilter->drawBlurRegion(canvas, getBlurRegion(layer), blurRect, blurredImage,
+                                            blurInput);
             }
-            if (layer->blurRegions.size() > 0) {
-                for (auto region : layer->blurRegions) {
-                    if (cachedBlurs[region.blurRadius]) {
-                        continue;
-                    }
+            for (auto region : layer->blurRegions) {
+                if (cachedBlurs[region.blurRadius] == nullptr) {
                     ATRACE_NAME("BlurRegion");
-                    auto blurredSurface =
-                            mBlurFilter->generate(canvas, surface, region.blurRadius, layerRect);
-                    cachedBlurs[region.blurRadius] = blurredSurface;
+                    cachedBlurs[region.blurRadius] =
+                            mBlurFilter->generate(grContext.get(), region.blurRadius, blurInput,
+                                                  blurRect);
                 }
+
+                mBlurFilter->drawBlurRegion(canvas, region, blurRect,
+                                            cachedBlurs[region.blurRadius], blurInput);
             }
         }
 
@@ -695,6 +775,7 @@
                            : layer->sourceDataspace)
                 : ui::Dataspace::UNKNOWN;
 
+        SkPaint paint;
         if (layer->source.buffer.buffer) {
             ATRACE_NAME("DrawImage");
             const auto& item = layer->source.buffer;
@@ -721,7 +802,7 @@
             // textureTansform was intended to be passed directly into a shader, so when
             // building the total matrix with the textureTransform we need to first
             // normalize it, then apply the textureTransform, then scale back up.
-            texMatrix.preScale(1.0f / bounds.getWidth(), 1.0f / bounds.getHeight());
+            texMatrix.preScale(1.0f / bounds.width(), 1.0f / bounds.height());
             texMatrix.postScale(image->width(), image->height());
 
             SkMatrix matrix;
@@ -791,14 +872,10 @@
 
         paint.setColorFilter(filter);
 
-        for (const auto effectRegion : layer->blurRegions) {
-            drawBlurRegion(canvas, effectRegion, layerRect, cachedBlurs[effectRegion.blurRadius]);
-        }
-
         if (layer->shadow.length > 0) {
             const auto rect = layer->geometry.roundedCornersRadius > 0
                     ? getSkRect(layer->geometry.roundedCornersCrop)
-                    : dest;
+                    : bounds;
             drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
         } else {
             // Shadows are assumed to live only on their own layer - it's not valid
@@ -809,7 +886,7 @@
             if (layer->geometry.roundedCornersRadius > 0) {
                 canvas->clipRRect(getRoundedRect(layer), true);
             }
-            canvas->drawRect(dest, paint);
+            canvas->drawRect(bounds, paint);
         }
         canvas->restore();
     }
@@ -817,7 +894,8 @@
     mCapture->endCapture();
     {
         ATRACE_NAME("flush surface");
-        surface->flush();
+        LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface);
+        activeSurface->flush();
     }
 
     if (drawFence != nullptr) {
@@ -874,6 +952,10 @@
                       .bottom = static_cast<int>(rect.fBottom)};
 }
 
+inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer) {
+    return layer->backgroundBlurRadius > 0 || layer->blurRegions.size();
+}
+
 inline SkColor SkiaGLRenderEngine::getSkColor(const vec4& color) {
     return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255);
 }
@@ -913,53 +995,6 @@
                               flags);
 }
 
-void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
-                                        const SkRect& layerRect, sk_sp<SkImage> blurredImage) {
-    ATRACE_CALL();
-
-    SkPaint paint;
-    paint.setAlpha(static_cast<int>(effectRegion.alpha * 255));
-    const auto matrix = getBlurShaderTransform(canvas, layerRect);
-    SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
-    paint.setShader(blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling,
-                                             &matrix));
-
-    auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
-                                 effectRegion.bottom);
-
-    if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
-        effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
-        const SkVector radii[4] =
-                {SkVector::Make(effectRegion.cornerRadiusTL, effectRegion.cornerRadiusTL),
-                 SkVector::Make(effectRegion.cornerRadiusTR, effectRegion.cornerRadiusTR),
-                 SkVector::Make(effectRegion.cornerRadiusBL, effectRegion.cornerRadiusBL),
-                 SkVector::Make(effectRegion.cornerRadiusBR, effectRegion.cornerRadiusBR)};
-        SkRRect roundedRect;
-        roundedRect.setRectRadii(rect, radii);
-        canvas->drawRRect(roundedRect, paint);
-    } else {
-        canvas->drawRect(rect, paint);
-    }
-}
-
-SkMatrix SkiaGLRenderEngine::getBlurShaderTransform(const SkCanvas* canvas,
-                                                    const SkRect& layerRect) {
-    // 1. Apply the blur shader matrix, which scales up the blured surface to its real size
-    auto matrix = mBlurFilter->getShaderMatrix();
-    // 2. Since the blurred surface has the size of the layer, we align it with the
-    // top left corner of the layer position.
-    matrix.postConcat(SkMatrix::Translate(layerRect.fLeft, layerRect.fTop));
-    // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the
-    // original surface orientation. The inverse matrix has to be applied to align the blur
-    // surface with the current orientation/position of the canvas.
-    SkMatrix drawInverse;
-    if (canvas->getTotalMatrix().invert(&drawInverse)) {
-        matrix.postConcat(drawInverse);
-    }
-
-    return matrix;
-}
-
 EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
                                                 EGLContext shareContext,
                                                 std::optional<ContextPriority> contextPriority,
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 810fc2a..5779ae6 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -61,6 +61,7 @@
     bool isProtected() const override { return mInProtectedContext; }
     bool supportsProtectedContent() const override;
     bool useProtectedContext(bool useProtectedContext) override;
+    bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
 
 protected:
     void dump(std::string& result) override;
@@ -81,17 +82,16 @@
     inline SkRect getSkRect(const Rect& layer);
     inline SkRRect getRoundedRect(const LayerSettings* layer);
     inline BlurRegion getBlurRegion(const LayerSettings* layer);
+    inline bool layerHasBlur(const LayerSettings* layer);
     inline SkColor getSkColor(const vec4& color);
     inline SkM44 getSkM44(const mat4& matrix);
     inline SkPoint3 getSkPoint3(const vec3& vector);
 
     base::unique_fd flush();
     bool waitFence(base::unique_fd fenceFd);
+    void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
     void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
                     const ShadowSettings& shadowSettings);
-    void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerRect,
-                        sk_sp<SkImage> blurredImage);
-    SkMatrix getBlurShaderTransform(const SkCanvas* canvas, const SkRect& layerRect);
     // If mUseColorManagement is correct and layer needsLinearEffect, it returns a linear runtime
     // shader. Otherwise it returns the input shader.
     sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader, const LayerSettings* layer,
diff --git a/libs/renderengine/skia/debug/SkiaCapture.cpp b/libs/renderengine/skia/debug/SkiaCapture.cpp
index e9cfead..40f5cf2 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.cpp
+++ b/libs/renderengine/skia/debug/SkiaCapture.cpp
@@ -41,11 +41,11 @@
     mTimer.stop();
 }
 
-SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) {
+SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) NO_THREAD_SAFETY_ANALYSIS {
     ATRACE_CALL();
 
     // If we are not running yet, set up.
-    if (!mCaptureRunning) {
+    if (CC_LIKELY(!mCaptureRunning)) {
         mTimerInterval = std::chrono::milliseconds(
                 base::GetIntProperty(PROPERTY_DEBUG_RENDERENGINE_CAPTURE_SKIA_MS, 0));
         // Set up the multi-frame capture. If we fail to set it up, then just return canvas.
@@ -56,7 +56,8 @@
         // Start the new timer. When timer expires, write to file.
         mTimer.setTimeout(
                 [this] {
-                    endCapture();
+                    const std::scoped_lock lock(mMutex);
+                    LOG_ALWAYS_FATAL_IF(mCurrentPageCanvas != nullptr);
                     writeToFile();
                     // To avoid going in circles, set the flag to 0. This way the capture can be
                     // restarted just by setting the flag and without restarting the process.
@@ -65,29 +66,82 @@
                 mTimerInterval);
     }
 
+    mMutex.lock();
+
     // Create a canvas pointer, fill it.
-    SkCanvas* pictureCanvas = mMultiPic->beginPage(surface->width(), surface->height());
+    mCurrentPageCanvas = mMultiPic->beginPage(surface->width(), surface->height());
 
     // Setting up an nway canvas is common to any kind of capture.
     mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
     mNwayCanvas->addCanvas(surface->getCanvas());
-    mNwayCanvas->addCanvas(pictureCanvas);
+    mNwayCanvas->addCanvas(mCurrentPageCanvas);
 
     return mNwayCanvas.get();
 }
 
-void SkiaCapture::endCapture() {
+void SkiaCapture::endCapture() NO_THREAD_SAFETY_ANALYSIS {
     ATRACE_CALL();
     // Don't end anything if we are not running.
-    if (!mCaptureRunning) {
+    if (CC_LIKELY(!mCaptureRunning)) {
         return;
     }
     // Reset the canvas pointer.
+    mCurrentPageCanvas = nullptr;
     mNwayCanvas.reset();
     // End page.
     if (mMultiPic) {
         mMultiPic->endPage();
     }
+    mMutex.unlock();
+}
+
+SkCanvas* SkiaCapture::tryOffscreenCapture(SkSurface* surface, OffscreenState* state) {
+    ATRACE_CALL();
+    // Don't start anything if we are not running.
+    if (CC_LIKELY(!mCaptureRunning)) {
+        return surface->getCanvas();
+    }
+
+    // Create a canvas pointer, fill it.
+    state->offscreenRecorder = std::make_unique<SkPictureRecorder>();
+    SkCanvas* pictureCanvas =
+            state->offscreenRecorder->beginRecording(surface->width(), surface->height());
+
+    // Setting up an nway canvas is common to any kind of capture.
+    state->offscreenCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
+    state->offscreenCanvas->addCanvas(surface->getCanvas());
+    state->offscreenCanvas->addCanvas(pictureCanvas);
+
+    return state->offscreenCanvas.get();
+}
+
+uint64_t SkiaCapture::endOffscreenCapture(OffscreenState* state) {
+    ATRACE_CALL();
+    // Don't end anything if we are not running.
+    if (CC_LIKELY(!mCaptureRunning)) {
+        return 0;
+    }
+
+    // compute the uniqueID for this capture
+    static std::atomic<uint64_t> nextID{1};
+    const uint64_t uniqueID = nextID.fetch_add(1, std::memory_order_relaxed);
+
+    // Reset the canvas pointer as we are no longer drawing into it
+    state->offscreenCanvas.reset();
+
+    // Record the offscreen as a picture in the currently active page.
+    SkRect bounds =
+            SkRect::Make(state->offscreenRecorder->getRecordingCanvas()->imageInfo().dimensions());
+    mCurrentPageCanvas
+            ->drawAnnotation(bounds,
+                             String8::format("OffscreenLayerDraw|%" PRId64, uniqueID).c_str(),
+                             nullptr);
+    mCurrentPageCanvas->drawPicture(state->offscreenRecorder->finishRecordingAsPicture());
+
+    // Reset the offscreen picture recorder
+    state->offscreenRecorder.reset();
+
+    return uniqueID;
 }
 
 void SkiaCapture::writeToFile() {
diff --git a/libs/renderengine/skia/debug/SkiaCapture.h b/libs/renderengine/skia/debug/SkiaCapture.h
index eaaf598..5e18e60 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.h
+++ b/libs/renderengine/skia/debug/SkiaCapture.h
@@ -18,8 +18,12 @@
 
 #include <SkDocument.h>
 #include <SkNWayCanvas.h>
+#include <SkPictureRecorder.h>
 #include <SkSurface.h>
+
 #include <chrono>
+#include <mutex>
+
 #include "CaptureTimer.h"
 #include "tools/SkSharingProc.h"
 
@@ -48,6 +52,16 @@
     // Returns whether the capture is running.
     bool isCaptureRunning() { return mCaptureRunning; }
 
+    // Offscreen state member variables are private to SkiaCapture, but the allocation
+    // and lifetime is managed by the caller. This enables nested offscreen
+    // captures to occur.
+    struct OffscreenState {
+        std::unique_ptr<SkPictureRecorder> offscreenRecorder;
+        std::unique_ptr<SkNWayCanvas> offscreenCanvas;
+    };
+    SkCanvas* tryOffscreenCapture(SkSurface* surface, OffscreenState* state);
+    uint64_t endOffscreenCapture(OffscreenState* state);
+
 private:
     // Performs the first-frame work of a multi frame SKP capture. Returns true if successful.
     bool setupMultiFrameCapture();
@@ -61,10 +75,16 @@
     std::unique_ptr<SkSharingSerialContext> mSerialContext;
     std::unique_ptr<SkNWayCanvas> mNwayCanvas;
 
+    SkCanvas* mCurrentPageCanvas = nullptr;
+
     // Capturing and interval control.
     bool mCaptureRunning = false;
     CaptureTimer mTimer;
     Interval mTimerInterval = 0ms;
+
+    // Mutex to ensure that a frame in progress when the timer fires is allowed to run to
+    // completion before we write the file to disk.
+    std::mutex mMutex;
 };
 
 } // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 87b1a7c..5960e48 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -20,6 +20,7 @@
 #include <SkCanvas.h>
 #include <SkData.h>
 #include <SkPaint.h>
+#include <SkRRect.h>
 #include <SkRuntimeEffect.h>
 #include <SkSize.h>
 #include <SkString.h>
@@ -34,17 +35,14 @@
 BlurFilter::BlurFilter() {
     SkString blurString(R"(
         in shader input;
-        uniform float in_inverseScale;
         uniform float2 in_blurOffset;
 
         half4 main(float2 xy) {
-            float2 scaled_xy = float2(xy.x * in_inverseScale, xy.y * in_inverseScale);
-
-            half4 c = sample(input, scaled_xy);
-            c += sample(input, scaled_xy + float2( in_blurOffset.x,  in_blurOffset.y));
-            c += sample(input, scaled_xy + float2( in_blurOffset.x, -in_blurOffset.y));
-            c += sample(input, scaled_xy + float2(-in_blurOffset.x,  in_blurOffset.y));
-            c += sample(input, scaled_xy + float2(-in_blurOffset.x, -in_blurOffset.y));
+            half4 c = sample(input, xy);
+            c += sample(input, xy + float2( in_blurOffset.x,  in_blurOffset.y));
+            c += sample(input, xy + float2( in_blurOffset.x, -in_blurOffset.y));
+            c += sample(input, xy + float2(-in_blurOffset.x,  in_blurOffset.y));
+            c += sample(input, xy + float2(-in_blurOffset.x, -in_blurOffset.y));
 
             return half4(c.rgb * 0.2, 1.0);
         }
@@ -55,10 +53,26 @@
         LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str());
     }
     mBlurEffect = std::move(blurEffect);
+
+    SkString mixString(R"(
+        in shader blurredInput;
+        in shader originalInput;
+        uniform float mixFactor;
+
+        half4 main(float2 xy) {
+            return half4(mix(sample(originalInput), sample(blurredInput), mixFactor));
+        }
+    )");
+
+    auto [mixEffect, mixError] = SkRuntimeEffect::Make(mixString);
+    if (!mixEffect) {
+        LOG_ALWAYS_FATAL("RuntimeShader error: %s", mixError.c_str());
+    }
+    mMixEffect = std::move(mixEffect);
 }
 
-sk_sp<SkImage> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
-                                    const uint32_t blurRadius, SkRect rect) const {
+sk_sp<SkImage> BlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius,
+                                    const sk_sp<SkImage> input, const SkRect& blurRect) const {
     // Kawase is an approximation of Gaussian, but it behaves differently from it.
     // A radius transformation is required for approximating them, and also to introduce
     // non-integer steps, necessary to smoothly interpolate large radii.
@@ -66,40 +80,110 @@
     float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius));
     float radiusByPasses = tmpRadius / (float)numberOfPasses;
 
-    SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)rect.width() * kInputScale,
-                                                        (float)rect.height() * kInputScale);
+    // create blur surface with the bit depth and colorspace of the original surface
+    SkImageInfo scaledInfo = input->imageInfo().makeWH(blurRect.width() * kInputScale,
+                                                       blurRect.height() * kInputScale);
 
     const float stepX = radiusByPasses;
     const float stepY = radiusByPasses;
 
-    // start by drawing and downscaling and doing the first blur pass
+    // For sampling Skia's API expects the inverse of what logically seems appropriate. In this
+    // case you might expect Translate(blurRect.fLeft, blurRect.fTop) X Scale(kInverseInputScale)
+    // but instead we must do the inverse.
+    SkMatrix blurMatrix = SkMatrix::Translate(-blurRect.fLeft, -blurRect.fTop);
+    blurMatrix.postScale(kInputScale, kInputScale);
+
+    // start by downscaling and doing the first blur pass
     SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
     SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
     blurBuilder.child("input") =
-            input->makeImageSnapshot(rect.round())
-                    ->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
-    blurBuilder.uniform("in_inverseScale") = kInverseInputScale;
-    blurBuilder.uniform("in_blurOffset") =
-            SkV2{stepX * kInverseInputScale, stepY * kInverseInputScale};
+            input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix);
+    blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale};
 
-    sk_sp<SkImage> tmpBlur(
-            blurBuilder.makeImage(canvas->recordingContext(), nullptr, scaledInfo, false));
+    sk_sp<SkImage> tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false));
 
     // And now we'll build our chain of scaled blur stages
-    blurBuilder.uniform("in_inverseScale") = 1.0f;
     for (auto i = 1; i < numberOfPasses; i++) {
         const float stepScale = (float)i * kInputScale;
         blurBuilder.child("input") =
                 tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
         blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
-        tmpBlur = blurBuilder.makeImage(canvas->recordingContext(), nullptr, scaledInfo, false);
+        tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false);
     }
 
     return tmpBlur;
 }
 
-SkMatrix BlurFilter::getShaderMatrix() const {
-    return SkMatrix::Scale(kInverseInputScale, kInverseInputScale);
+static SkMatrix getShaderTransform(const SkCanvas* canvas, const SkRect& blurRect, float scale) {
+    // 1. Apply the blur shader matrix, which scales up the blured surface to its real size
+    auto matrix = SkMatrix::Scale(scale, scale);
+    // 2. Since the blurred surface has the size of the layer, we align it with the
+    // top left corner of the layer position.
+    matrix.postConcat(SkMatrix::Translate(blurRect.fLeft, blurRect.fTop));
+    // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the
+    // original surface orientation. The inverse matrix has to be applied to align the blur
+    // surface with the current orientation/position of the canvas.
+    SkMatrix drawInverse;
+    if (canvas != nullptr && canvas->getTotalMatrix().invert(&drawInverse)) {
+        matrix.postConcat(drawInverse);
+    }
+    return matrix;
+}
+
+void BlurFilter::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
+                                const SkRect& blurRect, sk_sp<SkImage> blurredImage,
+                                sk_sp<SkImage> input) {
+    ATRACE_CALL();
+
+    SkPaint paint;
+    paint.setAlphaf(effectRegion.alpha);
+    if (effectRegion.alpha == 1.0f) {
+        paint.setBlendMode(SkBlendMode::kSrc);
+    }
+
+    const auto blurMatrix = getShaderTransform(canvas, blurRect, kInverseInputScale);
+    SkSamplingOptions linearSampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
+    const auto blurShader = blurredImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
+                                                     linearSampling, &blurMatrix);
+
+    if (effectRegion.blurRadius < kMaxCrossFadeRadius) {
+        // For sampling Skia's API expects the inverse of what logically seems appropriate. In this
+        // case you might expect the matrix to simply be the canvas matrix.
+        SkMatrix inputMatrix;
+        if (!canvas->getTotalMatrix().invert(&inputMatrix)) {
+            ALOGE("matrix was unable to be inverted");
+        }
+
+        SkRuntimeShaderBuilder blurBuilder(mMixEffect);
+        blurBuilder.child("blurredInput") = blurShader;
+        blurBuilder.child("originalInput") =
+                input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linearSampling,
+                                  inputMatrix);
+        blurBuilder.uniform("mixFactor") = effectRegion.blurRadius / kMaxCrossFadeRadius;
+
+        paint.setShader(blurBuilder.makeShader(nullptr, true));
+    } else {
+        paint.setShader(blurShader);
+    }
+
+    // TODO we should AA at least the drawRoundRect which would mean no SRC blending
+    // TODO this round rect calculation doesn't match the one used to draw in RenderEngine
+    auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
+                                 effectRegion.bottom);
+
+    if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
+        effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
+        const SkVector radii[4] =
+                {SkVector::Make(effectRegion.cornerRadiusTL, effectRegion.cornerRadiusTL),
+                 SkVector::Make(effectRegion.cornerRadiusTR, effectRegion.cornerRadiusTR),
+                 SkVector::Make(effectRegion.cornerRadiusBL, effectRegion.cornerRadiusBL),
+                 SkVector::Make(effectRegion.cornerRadiusBR, effectRegion.cornerRadiusBR)};
+        SkRRect roundedRect;
+        roundedRect.setRectRadii(rect, radii);
+        canvas->drawRRect(roundedRect, paint);
+    } else {
+        canvas->drawRect(rect, paint);
+    }
 }
 
 } // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index 08641c9..731ba11 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -20,6 +20,7 @@
 #include <SkImage.h>
 #include <SkRuntimeEffect.h>
 #include <SkSurface.h>
+#include <ui/BlurRegion.h>
 
 using namespace std;
 
@@ -48,13 +49,15 @@
     virtual ~BlurFilter(){};
 
     // Execute blur, saving it to a texture
-    sk_sp<SkImage> generate(SkCanvas* canvas, const sk_sp<SkSurface> input, const uint32_t radius,
-                            SkRect rect) const;
-    // Returns a matrix that should be applied to the blur shader
-    SkMatrix getShaderMatrix() const;
+    sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
+                            const sk_sp<SkImage> blurInput, const SkRect& blurRect) const;
+
+    void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& blurRect,
+                        sk_sp<SkImage> blurredImage, sk_sp<SkImage> input);
 
 private:
     sk_sp<SkRuntimeEffect> mBlurEffect;
+    sk_sp<SkRuntimeEffect> mMixEffect;
 };
 
 } // namespace skia
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index 51c7028..d0e19dd 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "librenderengine_test",
     defaults: ["skia_deps", "surfaceflinger_defaults"],
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 58afe6e..500a90b 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -914,13 +914,6 @@
 
 template <typename SourceVariant>
 void RenderEngineTest::fillBufferAndBlurBackground() {
-        char value[PROPERTY_VALUE_MAX];
-    property_get("ro.surface_flinger.supports_background_blur", value, "0");
-    if (!atoi(value)) {
-        // This device doesn't support blurs, no-op.
-        return;
-    }
-
     auto blurRadius = 50;
     auto center = DEFAULT_DISPLAY_WIDTH / 2;
 
@@ -950,15 +943,20 @@
     blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
     blurLayer.geometry.boundaries = fullscreenRect().toFloatRect();
     blurLayer.backgroundBlurRadius = blurRadius;
+    SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this);
     blurLayer.alpha = 0;
     layers.push_back(&blurLayer);
 
     invokeDraw(settings, layers);
 
-    expectBufferColor(Rect(center - 1, center - 5, center, center + 5), 150, 150, 0, 255,
-                      50 /* tolerance */);
-    expectBufferColor(Rect(center, center - 5, center + 1, center + 5), 150, 150, 0, 255,
-                      50 /* tolerance */);
+    // solid color
+    expectBufferColor(Rect(0, 0, 1, 1), 255, 0, 0, 255, 0 /* tolerance */);
+
+    if (mRE->supportsBackgroundBlur()) {
+        // blurred color (downsampling should result in the center color being close to 128)
+        expectBufferColor(Rect(center - 1, center - 5, center + 1, center + 5), 128, 128, 0, 255,
+                          10 /* tolerance */);
+    }
 }
 
 template <typename SourceVariant>
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 02ff06f..08b672a 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -144,6 +144,17 @@
     ASSERT_EQ(true, result);
 }
 
+TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsFalse) {
+    EXPECT_CALL(*mRenderEngine, supportsBackgroundBlur()).WillOnce(Return(false));
+    status_t result = mThreadedRE->supportsBackgroundBlur();
+    ASSERT_EQ(false, result);
+}
+
+TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsTrue) {
+    EXPECT_CALL(*mRenderEngine, supportsBackgroundBlur()).WillOnce(Return(true));
+    status_t result = mThreadedRE->supportsBackgroundBlur();
+    ASSERT_EQ(true, result);
+}
 TEST_F(RenderEngineThreadedTest, drawLayers) {
     renderengine::DisplaySettings settings;
     std::vector<const renderengine::LayerSettings*> layers;
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 3b97f56..f448135 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -315,6 +315,21 @@
     return resultFuture.get();
 }
 
+bool RenderEngineThreaded::supportsBackgroundBlur() {
+    std::promise<bool> resultPromise;
+    std::future<bool> resultFuture = resultPromise.get_future();
+    {
+        std::lock_guard lock(mThreadMutex);
+        mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+            ATRACE_NAME("REThreaded::supportsBackgroundBlur");
+            bool returnValue = instance.supportsBackgroundBlur();
+            resultPromise.set_value(returnValue);
+        });
+    }
+    mCondition.notify_one();
+    return resultFuture.get();
+}
+
 } // namespace threaded
 } // namespace renderengine
 } // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 8b1e2de..8279cbc 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -64,6 +64,7 @@
 
     void cleanFramebufferCache() override;
     int getContextPriority() override;
+    bool supportsBackgroundBlur() override;
 
 private:
     void threadMain(CreateInstanceFactory factory);
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index e8154a6..497c33c 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libsensor",
 
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index a6b0aaf..a6cacad 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -91,13 +91,14 @@
     }
 
     virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
-             int mode, const String16& opPackageName)
+             int mode, const String16& opPackageName, const String16& attributionTag)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
         data.writeString8(packageName);
         data.writeInt32(mode);
         data.writeString16(opPackageName);
+        data.writeString16(attributionTag);
         remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply);
         return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
     }
@@ -170,8 +171,9 @@
             String8 packageName = data.readString8();
             int32_t mode = data.readInt32();
             const String16& opPackageName = data.readString16();
+            const String16& attributionTag = data.readString16();
             sp<ISensorEventConnection> connection(createSensorEventConnection(packageName, mode,
-                    opPackageName));
+                    opPackageName, attributionTag));
             reply->writeStrongBinder(IInterface::asBinder(connection));
             return NO_ERROR;
         }
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index 9d817ae..240738d 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -468,6 +468,19 @@
     mUuid.i64[1] = 0;
 }
 
+void Sensor::capMinDelayMicros(int32_t cappedMinDelay) {
+    if (mMinDelay < cappedMinDelay) {
+        mMinDelay = cappedMinDelay;
+    }
+}
+
+void Sensor::capHighestDirectReportRateLevel(int32_t cappedRateLevel) {
+    if (cappedRateLevel < getHighestDirectReportRateLevel()) {
+        mFlags &= ~SENSOR_FLAG_MASK_DIRECT_REPORT;
+        mFlags |= cappedRateLevel << SENSOR_FLAG_SHIFT_DIRECT_REPORT;
+    }
+}
+
 int32_t Sensor::getId() const {
     return int32_t(mUuid.i64[0]);
 }
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index a4a5d13..62f4b4e 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -225,13 +225,14 @@
     return nullptr;
 }
 
-sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) {
+sp<SensorEventQueue> SensorManager::createEventQueue(
+    String8 packageName, int mode, String16 attributionTag) {
     sp<SensorEventQueue> queue;
 
     Mutex::Autolock _l(mLock);
     while (assertStateLocked() == NO_ERROR) {
-        sp<ISensorEventConnection> connection =
-                mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName);
+        sp<ISensorEventConnection> connection = mSensorServer->createSensorEventConnection(
+            packageName, mode, mOpPackageName, attributionTag);
         if (connection == nullptr) {
             // SensorService just died or the app doesn't have required permissions.
             ALOGE("createEventQueue: connection is NULL.");
diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h
index 402678f..ce5c672 100644
--- a/libs/sensor/include/sensor/ISensorServer.h
+++ b/libs/sensor/include/sensor/ISensorServer.h
@@ -45,7 +45,7 @@
     virtual Vector<Sensor> getDynamicSensorList(const String16& opPackageName) = 0;
 
     virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
-             int mode, const String16& opPackageName) = 0;
+             int mode, const String16& opPackageName, const String16& attributionTag) = 0;
     virtual int32_t isDataInjectionEnabled() = 0;
 
     virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 324d443..374b68f 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -104,6 +104,9 @@
     int32_t getId() const;
     void setId(int32_t id);
 
+    void capMinDelayMicros(int32_t cappedMinDelay);
+    void capHighestDirectReportRateLevel(int32_t cappedRateLevel);
+
     // LightFlattenable protocol
     inline bool isFixedSize() const { return false; }
     size_t getFlattenedSize() const;
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index f09c9c6..09ac7ed 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -59,7 +59,8 @@
     ssize_t getSensorList(Sensor const* const** list);
     ssize_t getDynamicSensorList(Vector<Sensor>& list);
     Sensor const* getDefaultSensor(int type);
-    sp<SensorEventQueue> createEventQueue(String8 packageName = String8(""), int mode = 0);
+    sp<SensorEventQueue> createEventQueue(
+        String8 packageName = String8(""), int mode = 0, String16 attributionTag = String16(""));
     bool isDataInjectionEnabled();
     int createDirectChannel(size_t size, int channelType, const native_handle_t *channelData);
     void destroyDirectChannel(int channelNativeHandle);
diff --git a/libs/sensor/tests/Android.bp b/libs/sensor/tests/Android.bp
index c9a7668..8fdb003 100644
--- a/libs/sensor/tests/Android.bp
+++ b/libs/sensor/tests/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "libsensor_test",
 
diff --git a/libs/sensorprivacy/Android.bp b/libs/sensorprivacy/Android.bp
index 4a606ff..00514c4 100644
--- a/libs/sensorprivacy/Android.bp
+++ b/libs/sensorprivacy/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libsensorprivacy",
 
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 714ee3e..ac0ae72 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -12,6 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_libs_ui_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_defaults {
     name: "libui-defaults",
     clang: true,
@@ -77,7 +94,6 @@
         "libarect",
         "libmath",
     ],
-
 }
 
 cc_library_shared {
@@ -105,7 +121,8 @@
     srcs: [
         "DebugUtils.cpp",
         "DeviceProductInfo.cpp",
-        "DisplayInfo.cpp",
+        "DisplayMode.cpp",
+        "DynamicDisplayInfo.cpp",
         "Fence.cpp",
         "FenceTime.cpp",
         "FrameStats.cpp",
@@ -120,6 +137,7 @@
         "PixelFormat.cpp",
         "PublicFormat.cpp",
         "Size.cpp",
+        "StaticDisplayInfo.cpp",
     ],
 
     include_dirs: [
diff --git a/libs/ui/DisplayMode.cpp b/libs/ui/DisplayMode.cpp
new file mode 100644
index 0000000..cf05dbf
--- /dev/null
+++ b/libs/ui/DisplayMode.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/DisplayMode.h>
+
+#include <cstdint>
+
+#include <ui/FlattenableHelpers.h>
+
+#define RETURN_IF_ERROR(op) \
+    if (const status_t status = (op); status != OK) return status;
+
+namespace android::ui {
+
+size_t DisplayMode::getFlattenedSize() const {
+    return FlattenableHelpers::getFlattenedSize(id) +
+            FlattenableHelpers::getFlattenedSize(resolution) +
+            FlattenableHelpers::getFlattenedSize(xDpi) +
+            FlattenableHelpers::getFlattenedSize(yDpi) +
+            FlattenableHelpers::getFlattenedSize(refreshRate) +
+            FlattenableHelpers::getFlattenedSize(appVsyncOffset) +
+            FlattenableHelpers::getFlattenedSize(sfVsyncOffset) +
+            FlattenableHelpers::getFlattenedSize(presentationDeadline) +
+            FlattenableHelpers::getFlattenedSize(group);
+}
+
+status_t DisplayMode::flatten(void* buffer, size_t size) const {
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, id));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, resolution));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, xDpi));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, yDpi));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, refreshRate));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, appVsyncOffset));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, sfVsyncOffset));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, presentationDeadline));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, group));
+    return OK;
+}
+
+status_t DisplayMode::unflatten(const void* buffer, size_t size) {
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &id));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &resolution));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &xDpi));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &yDpi));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &refreshRate));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &appVsyncOffset));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &sfVsyncOffset));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &presentationDeadline));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &group));
+    return OK;
+}
+
+} // namespace android::ui
diff --git a/libs/ui/DynamicDisplayInfo.cpp b/libs/ui/DynamicDisplayInfo.cpp
new file mode 100644
index 0000000..11acdae
--- /dev/null
+++ b/libs/ui/DynamicDisplayInfo.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/DynamicDisplayInfo.h>
+
+#include <cstdint>
+
+#include <ui/FlattenableHelpers.h>
+
+#define RETURN_IF_ERROR(op) \
+    if (const status_t status = (op); status != OK) return status;
+
+namespace android::ui {
+
+std::optional<ui::DisplayMode> DynamicDisplayInfo::getActiveDisplayMode() const {
+    for (const auto& currMode : supportedDisplayModes) {
+        if (currMode.id == activeDisplayModeId) {
+            return currMode;
+        }
+    }
+    return {};
+}
+
+size_t DynamicDisplayInfo::getFlattenedSize() const {
+    return FlattenableHelpers::getFlattenedSize(supportedDisplayModes) +
+            FlattenableHelpers::getFlattenedSize(activeDisplayModeId) +
+            FlattenableHelpers::getFlattenedSize(supportedColorModes) +
+            FlattenableHelpers::getFlattenedSize(activeColorMode) +
+            FlattenableHelpers::getFlattenedSize(hdrCapabilities);
+}
+
+status_t DynamicDisplayInfo::flatten(void* buffer, size_t size) const {
+    if (size < getFlattenedSize()) {
+        return NO_MEMORY;
+    }
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedDisplayModes));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeDisplayModeId));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedColorModes));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeColorMode));
+    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, hdrCapabilities));
+    return OK;
+}
+
+status_t DynamicDisplayInfo::unflatten(const void* buffer, size_t size) {
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedDisplayModes));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeDisplayModeId));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedColorModes));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeColorMode));
+    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &hdrCapabilities));
+    return OK;
+}
+
+} // namespace android::ui
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
index a5b3e89..aec2fac 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -23,10 +23,6 @@
 #pragma clang diagnostic ignored "-Wundefined-reinterpret-cast"
 #endif
 
-HdrCapabilities::~HdrCapabilities() = default;
-HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) noexcept = default;
-HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) noexcept = default;
-
 size_t HdrCapabilities::getFlattenedSize() const {
     return  sizeof(mMaxLuminance) +
             sizeof(mMaxAverageLuminance) +
diff --git a/libs/ui/DisplayInfo.cpp b/libs/ui/StaticDisplayInfo.cpp
similarity index 86%
rename from libs/ui/DisplayInfo.cpp
rename to libs/ui/StaticDisplayInfo.cpp
index 73a78af..b66b281 100644
--- a/libs/ui/DisplayInfo.cpp
+++ b/libs/ui/StaticDisplayInfo.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <ui/DisplayInfo.h>
+#include <ui/StaticDisplayInfo.h>
 
 #include <cstdint>
 
@@ -23,16 +23,16 @@
 #define RETURN_IF_ERROR(op) \
     if (const status_t status = (op); status != OK) return status;
 
-namespace android {
+namespace android::ui {
 
-size_t DisplayInfo::getFlattenedSize() const {
+size_t StaticDisplayInfo::getFlattenedSize() const {
     return FlattenableHelpers::getFlattenedSize(connectionType) +
             FlattenableHelpers::getFlattenedSize(density) +
             FlattenableHelpers::getFlattenedSize(secure) +
             FlattenableHelpers::getFlattenedSize(deviceProductInfo);
 }
 
-status_t DisplayInfo::flatten(void* buffer, size_t size) const {
+status_t StaticDisplayInfo::flatten(void* buffer, size_t size) const {
     if (size < getFlattenedSize()) {
         return NO_MEMORY;
     }
@@ -43,7 +43,7 @@
     return OK;
 }
 
-status_t DisplayInfo::unflatten(void const* buffer, size_t size) {
+status_t StaticDisplayInfo::unflatten(void const* buffer, size_t size) {
     RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &connectionType));
     RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &density));
     RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &secure));
@@ -51,4 +51,4 @@
     return OK;
 }
 
-} // namespace android
+} // namespace android::ui
diff --git a/libs/ui/include/ui/DisplayConfig.h b/libs/ui/include/ui/DisplayMode.h
similarity index 61%
rename from libs/ui/include/ui/DisplayConfig.h
rename to libs/ui/include/ui/DisplayMode.h
index d6fbaab..56f68e7 100644
--- a/libs/ui/include/ui/DisplayConfig.h
+++ b/libs/ui/include/ui/DisplayMode.h
@@ -16,15 +16,21 @@
 
 #pragma once
 
+#include <cstdint>
 #include <type_traits>
 
 #include <ui/Size.h>
+#include <utils/Flattenable.h>
 #include <utils/Timers.h>
 
-namespace android {
+namespace android::ui {
 
-// Configuration supported by physical display.
-struct DisplayConfig {
+// This value is going to be serialized over binder so we prefer a fixed width type.
+using DisplayModeId = int32_t;
+
+// Mode supported by physical display.
+struct DisplayMode : LightFlattenable<DisplayMode> {
+    DisplayModeId id;
     ui::Size resolution;
     float xDpi = 0;
     float yDpi = 0;
@@ -33,9 +39,12 @@
     nsecs_t appVsyncOffset = 0;
     nsecs_t sfVsyncOffset = 0;
     nsecs_t presentationDeadline = 0;
-    int configGroup = -1;
+    int32_t group = -1;
+
+    bool isFixedSize() const { return false; }
+    size_t getFlattenedSize() const;
+    status_t flatten(void* buffer, size_t size) const;
+    status_t unflatten(const void* buffer, size_t size);
 };
 
-static_assert(std::is_trivially_copyable_v<DisplayConfig>);
-
-} // namespace android
+} // namespace android::ui
diff --git a/libs/ui/include/ui/DynamicDisplayInfo.h b/libs/ui/include/ui/DynamicDisplayInfo.h
new file mode 100644
index 0000000..6c349b7
--- /dev/null
+++ b/libs/ui/include/ui/DynamicDisplayInfo.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "DisplayMode.h"
+
+#include <cstdint>
+#include <optional>
+#include <vector>
+
+#include <ui/GraphicTypes.h>
+#include <ui/HdrCapabilities.h>
+#include <utils/Flattenable.h>
+
+namespace android::ui {
+
+// Information about a physical display which may change on hotplug reconnect.
+struct DynamicDisplayInfo : LightFlattenable<DynamicDisplayInfo> {
+    std::vector<ui::DisplayMode> supportedDisplayModes;
+
+    // This struct is going to be serialized over binder, so
+    // we can't use size_t because it may have different width
+    // in the client process.
+    int32_t activeDisplayModeId;
+
+    std::vector<ui::ColorMode> supportedColorModes;
+    ui::ColorMode activeColorMode;
+    HdrCapabilities hdrCapabilities;
+
+    std::optional<ui::DisplayMode> getActiveDisplayMode() const;
+
+    bool isFixedSize() const { return false; }
+    size_t getFlattenedSize() const;
+    status_t flatten(void* buffer, size_t size) const;
+    status_t unflatten(const void* buffer, size_t size);
+};
+
+} // namespace android::ui
diff --git a/libs/ui/include/ui/FloatRect.h b/libs/ui/include/ui/FloatRect.h
index bec2552..5d329ea 100644
--- a/libs/ui/include/ui/FloatRect.h
+++ b/libs/ui/include/ui/FloatRect.h
@@ -48,6 +48,8 @@
     float top = 0.0f;
     float right = 0.0f;
     float bottom = 0.0f;
+
+    constexpr bool isEmpty() const { return !(left < right && top < bottom); }
 };
 
 inline bool operator==(const FloatRect& a, const FloatRect& b) {
diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h
index 65ac26c..813adde 100644
--- a/libs/ui/include/ui/HdrCapabilities.h
+++ b/libs/ui/include/ui/HdrCapabilities.h
@@ -36,18 +36,12 @@
         mMaxAverageLuminance(maxAverageLuminance),
         mMinLuminance(minLuminance) {}
 
-    // Make this move-constructable and move-assignable
-    HdrCapabilities(HdrCapabilities&& other) noexcept;
-    HdrCapabilities& operator=(HdrCapabilities&& other) noexcept;
-
     HdrCapabilities()
       : mSupportedHdrTypes(),
         mMaxLuminance(-1.0f),
         mMaxAverageLuminance(-1.0f),
         mMinLuminance(-1.0f) {}
 
-    ~HdrCapabilities();
-
     const std::vector<ui::Hdr>& getSupportedHdrTypes() const {
         return mSupportedHdrTypes;
     }
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/StaticDisplayInfo.h
similarity index 90%
rename from libs/ui/include/ui/DisplayInfo.h
rename to libs/ui/include/ui/StaticDisplayInfo.h
index 03e0a38..e86ca29 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/StaticDisplayInfo.h
@@ -17,17 +17,16 @@
 #pragma once
 
 #include <optional>
-#include <type_traits>
 
 #include <ui/DeviceProductInfo.h>
 #include <utils/Flattenable.h>
 
-namespace android {
+namespace android::ui {
 
 enum class DisplayConnectionType { Internal, External };
 
 // Immutable information about physical display.
-struct DisplayInfo : LightFlattenable<DisplayInfo> {
+struct StaticDisplayInfo : LightFlattenable<StaticDisplayInfo> {
     DisplayConnectionType connectionType = DisplayConnectionType::Internal;
     float density = 0.f;
     bool secure = false;
@@ -39,4 +38,4 @@
     status_t unflatten(void const* buffer, size_t size);
 };
 
-} // namespace android
+} // namespace android::ui
diff --git a/libs/ui/include/ui/StretchEffect.h b/libs/ui/include/ui/StretchEffect.h
new file mode 100644
index 0000000..0803df3
--- /dev/null
+++ b/libs/ui/include/ui/StretchEffect.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/Flattenable.h>
+#include "FloatRect.h"
+
+#include <math.h>
+#include <type_traits>
+
+namespace android {
+
+struct StretchEffect : public LightFlattenablePod<StretchEffect> {
+    FloatRect area = {0, 0, 0, 0};
+    float vectorX = 0;
+    float vectorY = 0;
+    float maxAmount = 0;
+
+    bool operator==(const StretchEffect& other) const {
+        return area == other.area && vectorX == other.vectorX && vectorY == other.vectorY &&
+                maxAmount == other.maxAmount;
+    }
+
+    static bool isZero(float value) {
+        constexpr float NON_ZERO_EPSILON = 0.001f;
+        return fabsf(value) <= NON_ZERO_EPSILON;
+    }
+
+    bool isNoOp() const { return isZero(vectorX) && isZero(vectorY); }
+
+    bool hasEffect() const { return !isNoOp(); }
+
+    void sanitize() {
+        // If the area is empty, or the max amount is zero, then reset back to defaults
+        if (area.isEmpty() || isZero(maxAmount)) {
+            *this = StretchEffect{};
+        }
+    }
+};
+
+static_assert(std::is_trivially_copyable<StretchEffect>::value,
+              "StretchEffect must be trivially copyable to be flattenable");
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/ui/include_private/ui/FlattenableHelpers.h b/libs/ui/include_private/ui/FlattenableHelpers.h
index 8e316d8..378f37f 100644
--- a/libs/ui/include_private/ui/FlattenableHelpers.h
+++ b/libs/ui/include_private/ui/FlattenableHelpers.h
@@ -29,20 +29,29 @@
 namespace android {
 
 struct FlattenableHelpers {
-    // Helpers for reading and writing POD structures
-    template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+    // Helpers for reading and writing POD structures which are not LightFlattenable.
+    template <class T,
+              typename = std::enable_if_t<
+                      std::conjunction_v<std::is_trivially_copyable<T>,
+                                         std::negation<std::is_base_of<LightFlattenable<T>, T>>>>>
     static constexpr size_t getFlattenedSize(const T&) {
         return sizeof(T);
     }
 
-    template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+    template <class T,
+              typename = std::enable_if_t<
+                      std::conjunction_v<std::is_trivially_copyable<T>,
+                                         std::negation<std::is_base_of<LightFlattenable<T>, T>>>>>
     static status_t flatten(void** buffer, size_t* size, const T& value) {
         if (*size < sizeof(T)) return NO_MEMORY;
         FlattenableUtils::write(*buffer, *size, value);
         return OK;
     }
 
-    template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+    template <class T,
+              typename = std::enable_if_t<
+                      std::conjunction_v<std::is_trivially_copyable<T>,
+                                         std::negation<std::is_base_of<LightFlattenable<T>, T>>>>>
     static status_t unflatten(const void** buffer, size_t* size, T* value) {
         if (*size < sizeof(T)) return NO_MEMORY;
         FlattenableUtils::read(*buffer, *size, *value);
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/DisplayInfo.h b/libs/ui/include_vndk/ui/DisplayInfo.h
deleted file mode 120000
index 75f14cf..0000000
--- a/libs/ui/include_vndk/ui/DisplayInfo.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/ui/DisplayInfo.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/libs/ui/include_vndk/ui/StaticDisplayInfo.h b/libs/ui/include_vndk/ui/StaticDisplayInfo.h
new file mode 120000
index 0000000..541a7a3
--- /dev/null
+++ b/libs/ui/include_vndk/ui/StaticDisplayInfo.h
@@ -0,0 +1 @@
+../../include/ui/StaticDisplayInfo.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index d005ce8..516aad8 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_libs_ui_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+}
+
 cc_test {
     name: "Region_test",
     shared_libs: ["libui"],
diff --git a/libs/ui/tests/FlattenableHelpers_test.cpp b/libs/ui/tests/FlattenableHelpers_test.cpp
index db32bc7..44e20b5 100644
--- a/libs/ui/tests/FlattenableHelpers_test.cpp
+++ b/libs/ui/tests/FlattenableHelpers_test.cpp
@@ -42,7 +42,7 @@
     }
 
     status_t unflatten(void const* buffer, size_t size) {
-        int value;
+        int32_t value;
         FlattenableUtils::read(buffer, size, value);
         ptr = std::make_unique<int32_t>(value);
         return OK;
@@ -132,5 +132,66 @@
     ASSERT_FALSE(valueRead.has_value());
 }
 
+// If a struct is both trivially copyable and light flattenable we should treat it
+// as LigthFlattenable.
+TEST_F(FlattenableHelpersTest, TriviallyCopyableAndLightFlattenableIsFlattenedAsLightFlattenable) {
+    static constexpr int32_t kSizeTag = 1234567;
+    static constexpr int32_t kFlattenTag = 987654;
+    static constexpr int32_t kUnflattenTag = 5926582;
+
+    struct LightFlattenableAndTriviallyCopyable
+          : LightFlattenable<LightFlattenableAndTriviallyCopyable> {
+        int32_t value;
+
+        bool isFixedSize() const { return true; }
+        size_t getFlattenedSize() const { return kSizeTag; }
+
+        status_t flatten(void* buffer, size_t size) const {
+            FlattenableUtils::write(buffer, size, kFlattenTag);
+            return OK;
+        }
+
+        status_t unflatten(void const*, size_t) {
+            value = kUnflattenTag;
+            return OK;
+        }
+    };
+
+    {
+        // Verify that getFlattenedSize uses the LightFlattenable overload
+        LightFlattenableAndTriviallyCopyable foo;
+        EXPECT_EQ(kSizeTag, FlattenableHelpers::getFlattenedSize(foo));
+    }
+
+    {
+        // Verify that flatten uses the LightFlattenable overload
+        std::vector<int8_t> buffer(sizeof(int32_t));
+        auto rawBuffer = reinterpret_cast<void*>(buffer.data());
+        size_t size = buffer.size();
+        LightFlattenableAndTriviallyCopyable foo;
+        ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, foo));
+
+        auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
+        int32_t value;
+        FlattenableHelpers::unflatten(&rawReadBuffer, &size, &value);
+        EXPECT_EQ(kFlattenTag, value);
+    }
+
+    {
+        // Verify that unflatten uses the LightFlattenable overload
+        std::vector<int8_t> buffer(sizeof(int32_t));
+        auto rawBuffer = reinterpret_cast<void*>(buffer.data());
+        size_t size = buffer.size();
+        int32_t value = 4;
+        ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
+
+        auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
+
+        LightFlattenableAndTriviallyCopyable foo;
+        FlattenableHelpers::unflatten(&rawReadBuffer, &size, &foo);
+        EXPECT_EQ(kUnflattenTag, foo.value);
+    }
+}
+
 } // namespace
 } // namespace android
diff --git a/libs/ui/tools/Android.bp b/libs/ui/tools/Android.bp
index fb46c2b..c28c303 100644
--- a/libs/ui/tools/Android.bp
+++ b/libs/ui/tools/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_libs_ui_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_libs_ui_license"],
+}
+
 cc_defaults {
     name: "libui_tools_default",
     clang_cflags: [
diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp
index 49bc6bf..83c250a 100644
--- a/libs/vibrator/Android.bp
+++ b/libs/vibrator/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library {
     name: "libvibrator",
     vendor_available: true,
diff --git a/libs/vibrator/fuzzer/Android.bp b/libs/vibrator/fuzzer/Android.bp
index 8020151..f2a313c 100644
--- a/libs/vibrator/fuzzer/Android.bp
+++ b/libs/vibrator/fuzzer/Android.bp
@@ -17,6 +17,15 @@
  *****************************************************************************
  */
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_fuzz {
     name: "vibrator_fuzzer",
 
diff --git a/libs/vr/Android.bp b/libs/vr/Android.bp
index e8176cf..b308895 100644
--- a/libs/vr/Android.bp
+++ b/libs/vr/Android.bp
@@ -1,3 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-BSD
+    //   legacy_notice
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 subdirs = [
     "*",
 ]
diff --git a/libs/vr/libbroadcastring/Android.bp b/libs/vr/libbroadcastring/Android.bp
index 13af470..2eb2f9f 100644
--- a/libs/vr/libbroadcastring/Android.bp
+++ b/libs/vr/libbroadcastring/Android.bp
@@ -1,3 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
     name: "libbroadcastring",
     clang: true,
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 37c19d4..45bdd35 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -12,6 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_headers {
     name: "libbufferhub_headers",
     export_include_dirs: ["include"],
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 77c7911..f372bd7 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -12,6 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 sourceFiles = [
     "buffer_hub_queue_client.cpp",
     "buffer_hub_queue_parcelable.cpp",
diff --git a/libs/vr/libbufferhubqueue/benchmarks/Android.bp b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
index ef1eed6..fc1f376 100644
--- a/libs/vr/libbufferhubqueue/benchmarks/Android.bp
+++ b/libs/vr/libbufferhubqueue/benchmarks/Android.bp
@@ -1,4 +1,15 @@
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_benchmark {
     srcs: ["buffer_transport_benchmark.cpp"],
     shared_libs: [
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index a337921..e883916 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -1,4 +1,15 @@
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 header_libraries = [
     "libdvr_headers",
 ]
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index 8c354fb..365a676 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -12,6 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 sourceFiles = [
     "display_client.cpp",
     "display_manager_client.cpp",
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index d5a19d3..83c30d7 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -13,6 +13,17 @@
 // limitations under the License.
 
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_headers {
     name: "libdvr_headers",
     export_include_dirs: ["include"],
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 3260447..4ed80a4 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -12,6 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     srcs: [
         "dvr_display_manager-test.cpp",
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index e751768..9e1e516 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -12,6 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 localIncludeFiles = [
     "include",
 ]
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 24ba830..c1f6da3 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_headers {
     name: "libpdx_headers",
     export_include_dirs: ["private"],
diff --git a/libs/vr/libpdx/fuzz/Android.bp b/libs/vr/libpdx/fuzz/Android.bp
index b36e0de..cc32b18 100644
--- a/libs/vr/libpdx/fuzz/Android.bp
+++ b/libs/vr/libpdx/fuzz/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_fuzz {
     name: "libpdx_service_dispatcher_fuzzer",
     clang: true,
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index b3534de..ea73d7a 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -1,3 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "pdx_default_transport_compiler_defaults",
     clang: true,
@@ -75,4 +86,3 @@
         "libpdx_default_transport",
     ],
 }
-
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index 1d6eea2..532d1a7 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -1,3 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
     name: "libpdx_uds",
     clang: true,
diff --git a/libs/vr/libperformance/Android.bp b/libs/vr/libperformance/Android.bp
index 35d3dea..5beee35 100644
--- a/libs/vr/libperformance/Android.bp
+++ b/libs/vr/libperformance/Android.bp
@@ -12,6 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 sourceFiles = [
     "performance_client.cpp",
     "performance_rpc.cpp",
diff --git a/libs/vr/libvr_manager/Android.bp b/libs/vr/libvr_manager/Android.bp
index 2cd6a28..6f2ada4 100644
--- a/libs/vr/libvr_manager/Android.bp
+++ b/libs/vr/libvr_manager/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
     name: "libvr_manager",
     srcs: [
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index abc64bd..8aca9a5 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -12,6 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 sourceFiles = [
     "acquired_buffer.cpp",
     "epoll_event_dispatcher.cpp",
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
index 7fafd3b..dafd354 100644
--- a/libs/vr/libvrflinger/tests/Android.bp
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -1,3 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 shared_libs = [
     "android.hardware.configstore-utils",
     "android.hardware.configstore@1.0",
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index 8542790..8f566a0 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -12,6 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 sourceFiles = [
     "pose_client.cpp",
     "latency_model.cpp",
@@ -52,4 +63,3 @@
     header_libs: ["libdvr_headers"],
     name: "libvrsensor",
 }
-
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 8b94f61..3878cb1 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -12,6 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-BSD
+    //   SPDX-license-identifier-MIT
+    //   legacy_notice
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 ndk_headers {
     name: "libEGL_headers",
     from: "include",
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 5d17561..7861d62 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -1,4 +1,13 @@
 // Build the ETC1 library
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library {
     name: "libETC1",
     srcs: ["ETC1/etc1.cpp"],
diff --git a/opengl/tests/Android.bp b/opengl/tests/Android.bp
index 639f351..da717bd 100644
--- a/opengl/tests/Android.bp
+++ b/opengl/tests/Android.bp
@@ -1,4 +1,16 @@
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-BSD
+    //   SPDX-license-identifier-MIT
+    //   legacy_notice
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 subdirs = [
     "angeles",
     "configdump",
@@ -16,4 +28,3 @@
     "hwc",
     "lib",
 ]
-
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
index e3912a8..51c9376 100644
--- a/opengl/tests/EGLTest/Android.bp
+++ b/opengl/tests/EGLTest/Android.bp
@@ -1,4 +1,13 @@
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
 
     name: "EGL_test",
diff --git a/opengl/tests/angeles/Android.bp b/opengl/tests/angeles/Android.bp
index 5c398a6..5b81501 100644
--- a/opengl/tests/angeles/Android.bp
+++ b/opengl/tests/angeles/Android.bp
@@ -1,5 +1,50 @@
 // Copyright 2006 The Android Open Source Project
 
+package {
+    default_applicable_licenses: [
+        "frameworks_native_opengl_tests_angeles_license",
+    ],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change included anything that looked like it might be a license
+// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
+//
+// Please consider removing redundant or irrelevant files from 'license_text:'.
+//
+// large-scale-change filtered out the below license kinds as false-positives:
+//   SPDX-license-identifier-LGPL
+//   SPDX-license-identifier-LGPL-2.1
+//   SPDX-license-identifier-LGPL-3.0
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_opengl_tests_angeles_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-BSD",
+        "SPDX-license-identifier-MIT",
+        "legacy_notice",
+    ],
+    license_text: [
+        "license-BSD.txt",
+        "license-LGPL.txt",
+        "license.txt",
+    ],
+}
+
 cc_test {
     name: "angeles",
 
diff --git a/opengl/tests/configdump/Android.bp b/opengl/tests/configdump/Android.bp
index ee967970..ffb0c1f 100644
--- a/opengl/tests/configdump/Android.bp
+++ b/opengl/tests/configdump/Android.bp
@@ -1,3 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "test-opengl-configdump",
 
diff --git a/opengl/tests/fillrate/Android.bp b/opengl/tests/fillrate/Android.bp
index 689cee4..e4bff01 100644
--- a/opengl/tests/fillrate/Android.bp
+++ b/opengl/tests/fillrate/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "test-opengl-fillrate",
 
diff --git a/opengl/tests/filter/Android.bp b/opengl/tests/filter/Android.bp
index 23241e1..3b92b37 100644
--- a/opengl/tests/filter/Android.bp
+++ b/opengl/tests/filter/Android.bp
@@ -1,3 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "test-opengl-filter",
 
diff --git a/opengl/tests/finish/Android.bp b/opengl/tests/finish/Android.bp
index be20851..c2dfbc3 100644
--- a/opengl/tests/finish/Android.bp
+++ b/opengl/tests/finish/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "test-opengl-finish",
 
diff --git a/opengl/tests/gl2_basic/Android.bp b/opengl/tests/gl2_basic/Android.bp
index f4538ad..c54bdf3 100644
--- a/opengl/tests/gl2_basic/Android.bp
+++ b/opengl/tests/gl2_basic/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "test-opengl-gl2_basic",
 
diff --git a/opengl/tests/gl2_cameraeye/Android.bp b/opengl/tests/gl2_cameraeye/Android.bp
index 00e00df..6b8ee85 100644
--- a/opengl/tests/gl2_cameraeye/Android.bp
+++ b/opengl/tests/gl2_cameraeye/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 android_app {
     name: "GL2CameraEye",
     // Only compile source java files in this apk.
diff --git a/opengl/tests/gl2_copyTexImage/Android.bp b/opengl/tests/gl2_copyTexImage/Android.bp
index 87fa7ea..0a84d25 100644
--- a/opengl/tests/gl2_copyTexImage/Android.bp
+++ b/opengl/tests/gl2_copyTexImage/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "test-opengl-gl2_copyTexImage",
 
diff --git a/opengl/tests/gl2_java/Android.bp b/opengl/tests/gl2_java/Android.bp
index a8e5d7d..a33075e 100644
--- a/opengl/tests/gl2_java/Android.bp
+++ b/opengl/tests/gl2_java/Android.bp
@@ -1,6 +1,15 @@
 //########################################################################
 // OpenGL ES 2.0 Java sample
 //########################################################################
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 android_app {
     name: "GL2Java",
     srcs: ["**/*.java"],
diff --git a/opengl/tests/gl2_jni/Android.bp b/opengl/tests/gl2_jni/Android.bp
index 8d4323f..79773cb 100644
--- a/opengl/tests/gl2_jni/Android.bp
+++ b/opengl/tests/gl2_jni/Android.bp
@@ -3,6 +3,15 @@
 // This makefile builds both an activity and a shared library.
 //########################################################################
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 android_app {
     name: "GL2JNI",
     srcs: ["**/*.java"],
diff --git a/opengl/tests/gl2_yuvtex/Android.bp b/opengl/tests/gl2_yuvtex/Android.bp
index b64d94d..fadf0e8 100644
--- a/opengl/tests/gl2_yuvtex/Android.bp
+++ b/opengl/tests/gl2_yuvtex/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "test-opengl-gl2_yuvtex",
 
diff --git a/opengl/tests/gl_basic/Android.bp b/opengl/tests/gl_basic/Android.bp
index 5eed17e..f777401 100644
--- a/opengl/tests/gl_basic/Android.bp
+++ b/opengl/tests/gl_basic/Android.bp
@@ -1,3 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "test-opengl-gl_basic",
 
diff --git a/opengl/tests/gl_jni/Android.bp b/opengl/tests/gl_jni/Android.bp
index 0cb129a..dc46483 100644
--- a/opengl/tests/gl_jni/Android.bp
+++ b/opengl/tests/gl_jni/Android.bp
@@ -4,6 +4,15 @@
 //########################################################################
 // Build activity
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 android_app {
     name: "GLJNI",
     srcs: ["**/*.java"],
diff --git a/opengl/tests/gl_perf/Android.bp b/opengl/tests/gl_perf/Android.bp
index 25a317c..ca0f7e8 100644
--- a/opengl/tests/gl_perf/Android.bp
+++ b/opengl/tests/gl_perf/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "test-opengl-gl2_perf",
 
diff --git a/opengl/tests/gl_perfapp/Android.bp b/opengl/tests/gl_perfapp/Android.bp
index 66afb6a..2f62346 100644
--- a/opengl/tests/gl_perfapp/Android.bp
+++ b/opengl/tests/gl_perfapp/Android.bp
@@ -2,6 +2,15 @@
 // OpenGL ES Perf App
 // This makefile builds both an activity and a shared library.
 //########################################################################
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 android_app {
     name: "GLPerf",
     srcs: ["**/*.java"],
diff --git a/opengl/tests/gl_yuvtex/Android.bp b/opengl/tests/gl_yuvtex/Android.bp
index 9b4924a..7844186 100644
--- a/opengl/tests/gl_yuvtex/Android.bp
+++ b/opengl/tests/gl_yuvtex/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "test-opengl-gl_yuvtex",
 
diff --git a/opengl/tests/gldual/Android.bp b/opengl/tests/gldual/Android.bp
index 1006d44..3d6e677 100644
--- a/opengl/tests/gldual/Android.bp
+++ b/opengl/tests/gldual/Android.bp
@@ -4,6 +4,15 @@
 //########################################################################
 // Build activity
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 android_app {
     name: "GLDual",
     srcs: ["**/*.java"],
diff --git a/opengl/tests/gralloc/Android.bp b/opengl/tests/gralloc/Android.bp
index 33c3dba..5fb4556 100644
--- a/opengl/tests/gralloc/Android.bp
+++ b/opengl/tests/gralloc/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "test-opengl-gralloc",
 
diff --git a/opengl/tests/hwc/Android.bp b/opengl/tests/hwc/Android.bp
index 55f058f..719eb11 100644
--- a/opengl/tests/hwc/Android.bp
+++ b/opengl/tests/hwc/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
 
     name: "hwc_tests_defaults",
diff --git a/opengl/tests/lib/Android.bp b/opengl/tests/lib/Android.bp
index 2f6095d..05c9397 100644
--- a/opengl/tests/lib/Android.bp
+++ b/opengl/tests/lib/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
 
     name: "libglTest",
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/opengl/tests/lighting1709/Android.bp b/opengl/tests/lighting1709/Android.bp
index e734dd1..79daa26 100644
--- a/opengl/tests/lighting1709/Android.bp
+++ b/opengl/tests/lighting1709/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 android_test {
     name: "LightingTest",
     srcs: ["**/*.java"],
diff --git a/opengl/tests/linetex/Android.bp b/opengl/tests/linetex/Android.bp
index dbc2cdb..61976e5 100644
--- a/opengl/tests/linetex/Android.bp
+++ b/opengl/tests/linetex/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "test-opengl-linetex",
     srcs: ["linetex.cpp"],
diff --git a/opengl/tests/swapinterval/Android.bp b/opengl/tests/swapinterval/Android.bp
index eed4dff..a76f4cf 100644
--- a/opengl/tests/swapinterval/Android.bp
+++ b/opengl/tests/swapinterval/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "test-opengl-swapinterval",
     srcs: ["swapinterval.cpp"],
diff --git a/opengl/tests/testFramerate/Android.bp b/opengl/tests/testFramerate/Android.bp
index 5aa83b0..4334d88 100644
--- a/opengl/tests/testFramerate/Android.bp
+++ b/opengl/tests/testFramerate/Android.bp
@@ -2,6 +2,15 @@
 // Test framerate and look for hiccups
 //########################################################################
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 android_app {
     name: "TestFramerate",
     srcs: ["**/*.java"],
diff --git a/opengl/tests/testLatency/Android.bp b/opengl/tests/testLatency/Android.bp
index c516dc3..473cb42 100644
--- a/opengl/tests/testLatency/Android.bp
+++ b/opengl/tests/testLatency/Android.bp
@@ -1,6 +1,15 @@
 //########################################################################
 // Test end-to-end latency.
 //########################################################################
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 android_app {
     name: "TestLatency",
     sdk_version: "8",
diff --git a/opengl/tests/testPauseResume/Android.bp b/opengl/tests/testPauseResume/Android.bp
index 810e895..8171e1f 100644
--- a/opengl/tests/testPauseResume/Android.bp
+++ b/opengl/tests/testPauseResume/Android.bp
@@ -1,4 +1,13 @@
 // OpenGL ES JNI sample
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 android_app {
     name: "TestEGL",
     srcs: ["**/*.java"],
diff --git a/opengl/tests/testViewport/Android.bp b/opengl/tests/testViewport/Android.bp
index 629b573..13ce3ad 100644
--- a/opengl/tests/testViewport/Android.bp
+++ b/opengl/tests/testViewport/Android.bp
@@ -2,6 +2,15 @@
 // OpenGL ES JNI sample
 // This makefile builds both an activity and a shared library.
 //########################################################################
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 android_app {
     name: "TestViewport",
     srcs: ["**/*.java"],
diff --git a/opengl/tests/textures/Android.bp b/opengl/tests/textures/Android.bp
index 84adda2..f113ff7 100644
--- a/opengl/tests/textures/Android.bp
+++ b/opengl/tests/textures/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "test-opengl-textures",
     srcs: ["textures.cpp"],
diff --git a/opengl/tests/tritex/Android.bp b/opengl/tests/tritex/Android.bp
index 390397b..759582c 100644
--- a/opengl/tests/tritex/Android.bp
+++ b/opengl/tests/tritex/Android.bp
@@ -1,3 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "test-opengl-tritex",
     srcs: ["tritex.cpp"],
diff --git a/services/audiomanager/Android.bp b/services/audiomanager/Android.bp
index 12ad47e..e6fb2c3 100644
--- a/services/audiomanager/Android.bp
+++ b/services/audiomanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libaudiomanager",
 
diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp
index c3da216..72bd292 100644
--- a/services/automotive/display/Android.bp
+++ b/services/automotive/display/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "android.frameworks.automotive.display@1.0-service",
     defaults: ["hidl_defaults"],
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/batteryservice/Android.bp b/services/batteryservice/Android.bp
index 66ee8ff..1e37991 100644
--- a/services/batteryservice/Android.bp
+++ b/services/batteryservice/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_headers {
     name: "libbatteryservice_headers",
     vendor_available: true,
diff --git a/services/displayservice/Android.bp b/services/displayservice/Android.bp
index 4d2d873..8681784 100644
--- a/services/displayservice/Android.bp
+++ b/services/displayservice/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libdisplayservicehidl",
 
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 9a9bca1..b9b6a19 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "gpuservice_defaults",
     cflags: [
diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp
index b875814..9842ed7 100644
--- a/services/gpuservice/bpfprogs/Android.bp
+++ b/services/gpuservice/bpfprogs/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 bpf {
     name: "gpu_mem.o",
     srcs: ["gpu_mem.c"],
diff --git a/services/gpuservice/gpumem/Android.bp b/services/gpuservice/gpumem/Android.bp
index b2230b6..830e53d 100644
--- a/services/gpuservice/gpumem/Android.bp
+++ b/services/gpuservice/gpumem/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libgpumem",
     srcs: [
diff --git a/services/gpuservice/gpustats/Android.bp b/services/gpuservice/gpustats/Android.bp
index f52602a..54291ad 100644
--- a/services/gpuservice/gpustats/Android.bp
+++ b/services/gpuservice/gpustats/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libgfxstats",
     srcs: [
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 9606daa..6d87c45 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "gpuservice_unittest",
     test_suites: ["device-tests"],
diff --git a/services/gpuservice/tracing/Android.bp b/services/gpuservice/tracing/Android.bp
index 919fed3..a1bc1ed 100644
--- a/services/gpuservice/tracing/Android.bp
+++ b/services/gpuservice/tracing/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libgpumemtracer",
     srcs: [
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index b640e9c..9b98a17 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -13,6 +13,15 @@
 // limitations under the License.
 
 // Default flags to be used throughout all libraries in inputflinger.
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "inputflinger_defaults",
     cflags: [
diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp
index bd275a7..ea37f4d 100644
--- a/services/inputflinger/benchmarks/Android.bp
+++ b/services/inputflinger/benchmarks/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_benchmark {
     name: "inputflinger_benchmarks",
     srcs: [
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index e5b131e..393f649 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_headers {
     name: "libinputdispatcher_headers",
     export_include_dirs: [
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 499f42e..45a007b 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -272,6 +272,7 @@
     std::string obscuringPackage;
     bool enabled;
     int32_t pid;
+    nsecs_t consumeTime; // time when the event was consumed by InputConsumer
 };
 
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 2909939..9898e9d 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1673,9 +1673,7 @@
 
     if (!mKeyIsWaitingForEventsTimeout.has_value()) {
         // Start the timer
-        ALOGD("Waiting to send key to %s because there are unprocessed events that may cause "
-              "focus to change",
-              focusedWindowName);
+        // Wait to send key because there are unprocessed events that may cause focus to change
         mKeyIsWaitingForEventsTimeout = currentTime +
                 std::chrono::duration_cast<std::chrono::nanoseconds>(KEY_WAITING_FOR_EVENTS_TIMEOUT)
                         .count();
@@ -2834,10 +2832,6 @@
  * This includes situations like the soft BACK button key. When the user releases (lifts up the
  * finger) the back button, then navigation bar will inject KEYCODE_BACK with ACTION_UP.
  * Both of those ACTION_UP events would not be logged
- * Monitors (both gesture and global): any gesture monitors or global monitors receiving events
- * will not be logged. This is omitted to reduce the amount of data printed.
- * If you see <none>, it's likely that one of the gesture monitors pilfered the event, and therefore
- * gesture monitor is the only connection receiving the remainder of the gesture.
  */
 void InputDispatcher::updateInteractionTokensLocked(const EventEntry& entry,
                                                     const std::vector<InputTarget>& targets) {
@@ -2867,8 +2861,8 @@
 
         sp<IBinder> token = target.inputChannel->getConnectionToken();
         sp<Connection> connection = getConnectionLocked(token);
-        if (connection == nullptr || connection->monitor) {
-            continue; // We only need to keep track of the non-monitor connections.
+        if (connection == nullptr) {
+            continue;
         }
         newConnectionTokens.insert(std::move(token));
         newConnections.emplace_back(connection);
@@ -2878,12 +2872,12 @@
     }
     mInteractionConnectionTokens = newConnectionTokens;
 
-    std::string windowList;
+    std::string targetList;
     for (const sp<Connection>& connection : newConnections) {
-        windowList += connection->getWindowName() + ", ";
+        targetList += connection->getWindowName() + ", ";
     }
-    std::string message = "Interaction with windows: " + windowList;
-    if (windowList.empty()) {
+    std::string message = "Interaction with: " + targetList;
+    if (targetList.empty()) {
         message += "<none>";
     }
     android_log_event_list(LOGTAG_INPUT_INTERACTION) << message << LOG_ID_EVENTS;
@@ -3113,7 +3107,7 @@
 
 void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
                                                 const sp<Connection>& connection, uint32_t seq,
-                                                bool handled) {
+                                                bool handled, nsecs_t consumeTime) {
 #if DEBUG_DISPATCH_CYCLE
     ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
           connection->getInputChannelName().c_str(), seq, toString(handled));
@@ -3125,7 +3119,7 @@
     }
 
     // Notify other system components and prepare to start the next dispatch cycle.
-    onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
+    onDispatchCycleFinishedLocked(currentTime, connection, seq, handled, consumeTime);
 }
 
 void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
@@ -3196,13 +3190,15 @@
             bool gotOne = false;
             status_t status;
             for (;;) {
-                uint32_t seq;
-                bool handled;
-                status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
+                std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)> callback =
+                        std::bind(&InputDispatcher::finishDispatchCycleLocked, d, currentTime,
+                                  connection, std::placeholders::_1, std::placeholders::_2,
+                                  std::placeholders::_3);
+
+                status = connection->inputPublisher.receiveFinishedSignal(callback);
                 if (status) {
                     break;
                 }
-                d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
                 gotOne = true;
             }
             if (gotOne) {
@@ -3219,8 +3215,7 @@
             }
         } else {
             // Monitor channels are never explicitly unregistered.
-            // We do it automatically when the remote endpoint is closed so don't warn
-            // about them.
+            // We do it automatically when the remote endpoint is closed so don't warn about them.
             const bool stillHaveWindowHandle =
                     d->getWindowHandleLocked(connection->inputChannel->getConnectionToken()) !=
                     nullptr;
@@ -4976,7 +4971,7 @@
                                                    bool notify) {
     sp<Connection> connection = getConnectionLocked(connectionToken);
     if (connection == nullptr) {
-        ALOGW("Attempted to unregister already unregistered input channel");
+        // Connection can be removed via socket hang up or an explicit call to 'removeInputChannel'
         return BAD_VALUE;
     }
 
@@ -5040,9 +5035,11 @@
         }
 
         TouchState& state = stateIt->second;
+        std::shared_ptr<InputChannel> requestingChannel;
         std::optional<int32_t> foundDeviceId;
         for (const TouchedMonitor& touchedMonitor : state.gestureMonitors) {
             if (touchedMonitor.monitor.inputChannel->getConnectionToken() == token) {
+                requestingChannel = touchedMonitor.monitor.inputChannel;
                 foundDeviceId = state.deviceId;
             }
         }
@@ -5058,13 +5055,19 @@
                                    "gesture monitor stole pointer stream");
         options.deviceId = deviceId;
         options.displayId = displayId;
+        std::string canceledWindows = "[";
         for (const TouchedWindow& window : state.windows) {
             std::shared_ptr<InputChannel> channel =
                     getInputChannelLocked(window.windowHandle->getToken());
             if (channel != nullptr) {
                 synthesizeCancelationEventsForInputChannelLocked(channel, options);
+                canceledWindows += channel->getName() + ", ";
             }
         }
+        canceledWindows += "]";
+        ALOGI("Monitor %s is stealing touch from %s", requestingChannel->getName().c_str(),
+              canceledWindows.c_str());
+
         // Then clear the current touch state so we stop dispatching to them as well.
         state.filterNonMonitors();
     }
@@ -5154,13 +5157,14 @@
 
 void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
                                                     const sp<Connection>& connection, uint32_t seq,
-                                                    bool handled) {
+                                                    bool handled, nsecs_t consumeTime) {
     std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
             &InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
     commandEntry->connection = connection;
     commandEntry->eventTime = currentTime;
     commandEntry->seq = seq;
     commandEntry->handled = handled;
+    commandEntry->consumeTime = consumeTime;
     postCommandLocked(std::move(commandEntry));
 }
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index c93d74e..83094c2 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -528,7 +528,7 @@
     void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
             REQUIRES(mLock);
     void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
-                                   uint32_t seq, bool handled) REQUIRES(mLock);
+                                   uint32_t seq, bool handled, nsecs_t consumeTime) REQUIRES(mLock);
     void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
                                         bool notify) REQUIRES(mLock);
     void drainDispatchQueue(std::deque<DispatchEntry*>& queue);
@@ -578,7 +578,8 @@
 
     // Interesting events that we might like to log or tell the framework about.
     void onDispatchCycleFinishedLocked(nsecs_t currentTime, const sp<Connection>& connection,
-                                       uint32_t seq, bool handled) REQUIRES(mLock);
+                                       uint32_t seq, bool handled, nsecs_t consumeTime)
+            REQUIRES(mLock);
     void onDispatchCycleBrokenLocked(nsecs_t currentTime, const sp<Connection>& connection)
             REQUIRES(mLock);
     void onFocusChangedLocked(const FocusResolver::FocusChanges& changes) REQUIRES(mLock);
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index 9e797e4..18d0226 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libinputflingerhost",
 
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 7f979f2..518e295 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_headers {
     name: "libinputreader_headers",
     export_include_dirs: [
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 8fc6f4a..574f651 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -520,7 +520,8 @@
 }
 
 void InputDevice::notifyReset(nsecs_t when) {
-    mContext->notifyDeviceReset(when, mId);
+    NotifyDeviceResetArgs args(mContext->getNextId(), when, mId);
+    mContext->getListener()->notifyDeviceReset(&args);
 }
 
 std::optional<int32_t> InputDevice::getAssociatedDisplayId() {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index c044393..14fb77b 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -339,7 +339,8 @@
     updateGlobalMetaStateLocked();
 
     // Enqueue configuration changed.
-    mContext.notifyConfigurationChanged(when);
+    NotifyConfigurationChangedArgs args(mContext.getNextId(), when);
+    mQueuedListener->notifyConfigurationChanged(&args);
 }
 
 void InputReader::refreshConfigurationLocked(uint32_t changes) {
@@ -366,7 +367,9 @@
     }
 
     if (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE) {
-        mContext.notifyPointerCaptureChanged(now, mConfig.pointerCapture);
+        const NotifyPointerCaptureChangedArgs args(mContext.getNextId(), now,
+                                                   mConfig.pointerCapture);
+        mQueuedListener->notifyPointerCaptureChanged(&args);
     }
 }
 
@@ -885,69 +888,16 @@
     return mReader->mPolicy.get();
 }
 
+InputListenerInterface* InputReader::ContextImpl::getListener() {
+    return mReader->mQueuedListener.get();
+}
+
 EventHubInterface* InputReader::ContextImpl::getEventHub() {
     return mReader->mEventHub.get();
 }
 
-void InputReader::ContextImpl::notifyConfigurationChanged(nsecs_t when) {
-    NotifyConfigurationChangedArgs args(mIdGenerator.nextId(), when);
-    mReader->mQueuedListener->notifyConfigurationChanged(&args);
-}
-
-void InputReader::ContextImpl::notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source,
-                                         int32_t displayId, uint32_t policyFlags, int32_t action,
-                                         int32_t flags, int32_t keyCode, int32_t scanCode,
-                                         int32_t metaState, nsecs_t downTime) {
-    NotifyKeyArgs args(mIdGenerator.nextId(), eventTime, deviceId, source, displayId, policyFlags,
-                       action, flags, keyCode, scanCode, metaState, downTime);
-    mReader->mQueuedListener->notifyKey(&args);
-}
-void InputReader::ContextImpl::notifyMotion(
-        nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
-        uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags,
-        int32_t metaState, int32_t buttonState, MotionClassification classification,
-        int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties,
-        const PointerCoords* pointerCoords, float xPrecision, float yPrecision,
-        float xCursorPosition, float yCursorPosition, nsecs_t downTime,
-        const std::vector<TouchVideoFrame>& videoFrames) {
-    NotifyMotionArgs args(mIdGenerator.nextId(), eventTime, deviceId, source, displayId,
-                          policyFlags, action, actionButton, flags, metaState, buttonState,
-                          classification, edgeFlags, pointerCount, pointerProperties, pointerCoords,
-                          xPrecision, yPrecision, xCursorPosition, yCursorPosition, downTime,
-                          videoFrames);
-    mReader->mQueuedListener->notifyMotion(&args);
-}
-
-void InputReader::ContextImpl::notifySensor(nsecs_t when, int32_t deviceId,
-                                            InputDeviceSensorType sensorType,
-                                            InputDeviceSensorAccuracy accuracy,
-                                            bool accuracyChanged, nsecs_t timestamp,
-                                            std::vector<float> values) {
-    NotifySensorArgs args(mIdGenerator.nextId(), when, deviceId, AINPUT_SOURCE_SENSOR, sensorType,
-                          accuracy, accuracyChanged, timestamp, std::move(values));
-    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,
-                          switchMask);
-    mReader->mQueuedListener->notifySwitch(&args);
-}
-
-void InputReader::ContextImpl::notifyDeviceReset(nsecs_t when, int32_t deviceId) {
-    NotifyDeviceResetArgs args(mIdGenerator.nextId(), when, deviceId);
-    mReader->mQueuedListener->notifyDeviceReset(&args);
-}
-
-void InputReader::ContextImpl::notifyPointerCaptureChanged(nsecs_t when, bool hasCapture) {
-    const NotifyPointerCaptureChangedArgs args(mIdGenerator.nextId(), when, hasCapture);
-    mReader->mQueuedListener->notifyPointerCaptureChanged(&args);
+int32_t InputReader::ContextImpl::getNextId() {
+    return mIdGenerator.nextId();
 }
 
 } // namespace android
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 5f78149..81e3e9a 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -131,31 +131,11 @@
         void dispatchExternalStylusState(const StylusState& outState)
                 NO_THREAD_SAFETY_ANALYSIS override;
         InputReaderPolicyInterface* getPolicy() NO_THREAD_SAFETY_ANALYSIS override;
+        InputListenerInterface* getListener() NO_THREAD_SAFETY_ANALYSIS override;
         EventHubInterface* getEventHub() NO_THREAD_SAFETY_ANALYSIS override;
+        int32_t getNextId() NO_THREAD_SAFETY_ANALYSIS override;
         void updateLedMetaState(int32_t metaState) NO_THREAD_SAFETY_ANALYSIS override;
         int32_t getLedMetaState() NO_THREAD_SAFETY_ANALYSIS override;
-
-        // Send events to InputListener interface
-        void notifyConfigurationChanged(nsecs_t when) override;
-        void notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
-                       uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
-                       int32_t scanCode, int32_t metaState, nsecs_t downTime) override;
-        void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
-                          uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags,
-                          int32_t metaState, int32_t buttonState,
-                          MotionClassification classification, int32_t edgeFlags,
-                          uint32_t pointerCount, const PointerProperties* pointerProperties,
-                          const PointerCoords* pointerCoords, float xPrecision, float yPrecision,
-                          float xCursorPosition, float yCursorPosition, nsecs_t downTime,
-                          const std::vector<TouchVideoFrame>& videoFrames) override;
-        void notifySwitch(nsecs_t eventTime, uint32_t switchValues, uint32_t switchMask) override;
-        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;
-
     } mContext;
 
     friend class ContextImpl;
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index e6ea523..dc807f7 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -55,34 +55,13 @@
     virtual void dispatchExternalStylusState(const StylusState& outState) = 0;
 
     virtual InputReaderPolicyInterface* getPolicy() = 0;
+    virtual InputListenerInterface* getListener() = 0;
     virtual EventHubInterface* getEventHub() = 0;
 
+    virtual int32_t getNextId() = 0;
+
     virtual void updateLedMetaState(int32_t metaState) = 0;
     virtual int32_t getLedMetaState() = 0;
-
-    // Send events to InputListener interface
-
-    virtual void notifyConfigurationChanged(nsecs_t when) = 0;
-    virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
-                           uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
-                           int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
-    virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source,
-                              int32_t displayId, uint32_t policyFlags, int32_t action,
-                              int32_t actionButton, int32_t flags, int32_t metaState,
-                              int32_t buttonState, MotionClassification classification,
-                              int32_t edgeFlags, uint32_t pointerCount,
-                              const PointerProperties* pointerProperties,
-                              const PointerCoords* pointerCoords, float xPrecision,
-                              float yPrecision, float xCursorPosition, float yCursorPosition,
-                              nsecs_t downTime,
-                              const std::vector<TouchVideoFrame>& videoFrames) = 0;
-    virtual void notifySwitch(nsecs_t eventTime, uint32_t switchValues, uint32_t switchMask) = 0;
-    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;
 };
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 7f7b33c..254b64b 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -175,7 +175,8 @@
         }
         bumpGeneration();
         if (changes) {
-            getContext()->notifyDeviceReset(when, getDeviceId());
+            NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
+            getListener()->notifyDeviceReset(&args);
         }
     }
 
@@ -382,35 +383,40 @@
             while (!released.isEmpty()) {
                 int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
                 buttonState &= ~actionButton;
-                getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                           AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
-                                           metaState, buttonState, MotionClassification::NONE,
-                                           AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
-                                           &pointerCoords, mXPrecision, mYPrecision,
-                                           xCursorPosition, yCursorPosition, downTime,
-                                           /* videoFrames */ {});
+                NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, getDeviceId(),
+                                             mSource, displayId, policyFlags,
+                                             AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
+                                             metaState, buttonState, MotionClassification::NONE,
+                                             AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+                                             &pointerCoords, mXPrecision, mYPrecision,
+                                             xCursorPosition, yCursorPosition, downTime,
+                                             /* videoFrames */ {});
+                getListener()->notifyMotion(&releaseArgs);
             }
         }
 
-        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                   motionEventAction, 0, 0, metaState, currentButtonState,
-                                   MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                                   &pointerProperties, &pointerCoords, mXPrecision, mYPrecision,
-                                   xCursorPosition, yCursorPosition, downTime,
-                                   /* videoFrames */ {});
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,
+                              MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                              &pointerProperties, &pointerCoords, mXPrecision, mYPrecision,
+                              xCursorPosition, yCursorPosition, downTime,
+                              /* videoFrames */ {});
+        getListener()->notifyMotion(&args);
 
         if (buttonsPressed) {
             BitSet32 pressed(buttonsPressed);
             while (!pressed.isEmpty()) {
                 int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
                 buttonState |= actionButton;
-                getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                NotifyMotionArgs pressArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+                                           displayId, policyFlags,
                                            AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
                                            metaState, buttonState, MotionClassification::NONE,
                                            AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                            &pointerCoords, mXPrecision, mYPrecision,
                                            xCursorPosition, yCursorPosition, downTime,
                                            /* videoFrames */ {});
+                getListener()->notifyMotion(&pressArgs);
             }
         }
 
@@ -418,12 +424,13 @@
 
         // Send hover move after UP to tell the application that the mouse is hovering now.
         if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
-            getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                       AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
-                                       currentButtonState, MotionClassification::NONE,
+            NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+                                       displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+                                       0, metaState, currentButtonState, MotionClassification::NONE,
                                        AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                        &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
                                        yCursorPosition, downTime, /* videoFrames */ {});
+            getListener()->notifyMotion(&hoverArgs);
         }
 
         // Send scroll events.
@@ -431,12 +438,13 @@
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
-            getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                       AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
-                                       currentButtonState, MotionClassification::NONE,
-                                       AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
-                                       &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
-                                       yCursorPosition, downTime, /* videoFrames */ {});
+            NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+                                        displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
+                                        metaState, currentButtonState, MotionClassification::NONE,
+                                        AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+                                        &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
+                                        yCursorPosition, downTime, /* videoFrames */ {});
+            getListener()->notifyMotion(&scrollArgs);
         }
     }
 
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 44af998..1cc5979 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -19,6 +19,7 @@
 
 #include "EventHub.h"
 #include "InputDevice.h"
+#include "InputListener.h"
 #include "InputReaderContext.h"
 #include "StylusState.h"
 #include "VibrationElement.h"
@@ -47,6 +48,7 @@
     inline const std::string getDeviceName() { return mDeviceContext.getName(); }
     inline InputReaderContext* getContext() { return mDeviceContext.getContext(); }
     inline InputReaderPolicyInterface* getPolicy() { return getContext()->getPolicy(); }
+    inline InputListenerInterface* getListener() { return getContext()->getListener(); }
 
     virtual uint32_t getSources() = 0;
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 28f29e0..37aa140 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -337,12 +337,13 @@
     // TODO: Use the input device configuration to control this behavior more finely.
     uint32_t policyFlags = 0;
 
-    getContext()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE,
-                               policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
-                               MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                               &pointerProperties, &pointerCoords, 0, 0,
-                               AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                               AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
+    NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_JOYSTICK,
+                          ADISPLAY_ID_NONE, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
+                          buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                          &pointerProperties, &pointerCoords, 0, 0,
+                          AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                          AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
+    getListener()->notifyMotion(&args);
 }
 
 void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis,
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 03d7405..8b9f235 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -350,9 +350,10 @@
         policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
     }
 
-    getContext()->notifyKey(when, getDeviceId(), mSource, getDisplayId(), policyFlags,
-                            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
-                            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
+    NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(),
+                       policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
+                       AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
+    getListener()->notifyKey(&args);
 }
 
 ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 3f8a364..594ff42 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -121,12 +121,13 @@
         int32_t metaState = getContext()->getGlobalMetaState();
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor);
 
-        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                   AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
-                                   /* buttonState */ 0, MotionClassification::NONE,
-                                   AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
-                                   &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                   AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
+        NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+                                    displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
+                                    metaState, /* buttonState */ 0, MotionClassification::NONE,
+                                    AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+                                    &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                    AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
+        getListener()->notifyMotion(&scrollArgs);
     }
 
     mRotaryEncoderScrollAccumulator.finishSync();
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index 68c1e40..7ac2dec 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -405,10 +405,13 @@
             // Convert to Android unit
             convertFromLinuxToAndroid(values, sensorType);
             // Notify dispatcher for sensor event
-            getContext()->notifySensor(when, getDeviceId(), sensorType, sensor.sensorInfo.accuracy,
-                                       sensor.accuracy !=
-                                               sensor.sensorInfo.accuracy /* accuracyChanged */,
-                                       timestamp /* hwTimestamp */, std::move(values));
+            NotifySensorArgs args(getContext()->getNextId(), when, getDeviceId(),
+                                  AINPUT_SOURCE_SENSOR, sensorType, sensor.sensorInfo.accuracy,
+                                  sensor.accuracy !=
+                                          sensor.sensorInfo.accuracy /* accuracyChanged */,
+                                  timestamp /* hwTimestamp */, values);
+
+            getListener()->notifySensor(&args);
             sensor.lastSampleTimeNs = timestamp;
             sensor.accuracy = sensor.sensorInfo.accuracy;
         }
diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
index 07de244..4f73681 100644
--- a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
@@ -56,7 +56,10 @@
 void SwitchInputMapper::sync(nsecs_t when) {
     if (mUpdatedSwitchMask) {
         uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask;
-        getContext()->notifySwitch(when, updatedSwitchValues, mUpdatedSwitchMask);
+        NotifySwitchArgs args(getContext()->getNextId(), when, 0 /*policyFlags*/,
+                              updatedSwitchValues, mUpdatedSwitchMask);
+        getListener()->notifySwitch(&args);
+
         mUpdatedSwitchMask = 0;
     }
 }
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index ff6341f..a86443d 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -66,8 +66,9 @@
          (currentButtonState & buttonState)) ||
         (action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) &&
          !(currentButtonState & buttonState))) {
-        context->notifyKey(when, deviceId, source, displayId, policyFlags, action, 0 /*flags*/,
-                           keyCode, 0 /*scanCode*/, context->getGlobalMetaState(), when);
+        NotifyKeyArgs args(context->getNextId(), when, deviceId, source, displayId, policyFlags,
+                           action, 0, keyCode, 0, context->getGlobalMetaState(), when);
+        context->getListener()->notifyKey(&args);
     }
 }
 
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 1a17bef..d1df37b 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -397,7 +397,8 @@
     if (changes && resetNeeded) {
         // Send reset, unless this is the first time the device has been configured,
         // in which case the reader will call reset itself after all mappers are ready.
-        getContext()->notifyDeviceReset(when, getDeviceId());
+        NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
+        getListener()->notifyDeviceReset(&args);
     }
 }
 
@@ -1845,9 +1846,10 @@
     int32_t metaState = getContext()->getGlobalMetaState();
     policyFlags |= POLICY_FLAG_VIRTUAL;
 
-    getContext()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, mViewport.displayId,
-                            policyFlags, keyEventAction, keyEventFlags, keyCode, scanCode,
-                            metaState, downTime);
+    NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_KEYBOARD,
+                       mViewport.displayId, policyFlags, keyEventAction, keyEventFlags, keyCode,
+                       scanCode, metaState, downTime);
+    getListener()->notifyKey(&args);
 }
 
 void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) {
@@ -2526,11 +2528,12 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
 
         const int32_t displayId = mPointerController->getDisplayId();
-        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                   AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState,
-                                   MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                                   &pointerProperties, &pointerCoords, 0, 0, x, y,
-                                   mPointerGesture.downTime, /* videoFrames */ {});
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+                              buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
+                              1, &pointerProperties, &pointerCoords, 0, 0, x, y,
+                              mPointerGesture.downTime, /* videoFrames */ {});
+        getListener()->notifyMotion(&args);
     }
 
     // Update state.
@@ -3445,28 +3448,28 @@
         mPointerSimple.down = false;
 
         // Send up.
-        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                   AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
-                                   mLastRawState.buttonState, MotionClassification::NONE,
-                                   AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
-                                   &mPointerSimple.lastCoords, mOrientedXPrecision,
-                                   mOrientedYPrecision, xCursorPosition, yCursorPosition,
-                                   mPointerSimple.downTime,
-                                   /* videoFrames */ {});
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
+                              mLastRawState.buttonState, MotionClassification::NONE,
+                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
+                              &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
+                              xCursorPosition, yCursorPosition, mPointerSimple.downTime,
+                              /* videoFrames */ {});
+        getListener()->notifyMotion(&args);
     }
 
     if (mPointerSimple.hovering && !hovering) {
         mPointerSimple.hovering = false;
 
         // Send hover exit.
-        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                   AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
-                                   mLastRawState.buttonState, MotionClassification::NONE,
-                                   AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
-                                   &mPointerSimple.lastCoords, mOrientedXPrecision,
-                                   mOrientedYPrecision, xCursorPosition, yCursorPosition,
-                                   mPointerSimple.downTime,
-                                   /* videoFrames */ {});
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
+                              mLastRawState.buttonState, MotionClassification::NONE,
+                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
+                              &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
+                              xCursorPosition, yCursorPosition, mPointerSimple.downTime,
+                              /* videoFrames */ {});
+        getListener()->notifyMotion(&args);
     }
 
     if (down) {
@@ -3475,24 +3478,25 @@
             mPointerSimple.downTime = when;
 
             // Send down.
-            getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                       AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState,
-                                       mCurrentRawState.buttonState, MotionClassification::NONE,
-                                       AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                                       &mPointerSimple.currentProperties,
-                                       &mPointerSimple.currentCoords, mOrientedXPrecision,
-                                       mOrientedYPrecision, xCursorPosition, yCursorPosition,
-                                       mPointerSimple.downTime, /* videoFrames */ {});
+            NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource,
+                                  displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0,
+                                  metaState, mCurrentRawState.buttonState,
+                                  MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                                  &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+                                  mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+                                  yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+            getListener()->notifyMotion(&args);
         }
 
         // Send move.
-        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                   AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
-                                   mCurrentRawState.buttonState, MotionClassification::NONE,
-                                   AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                                   &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
-                                   mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
-                                   yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
+                              mCurrentRawState.buttonState, MotionClassification::NONE,
+                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
+                              &mPointerSimple.currentCoords, mOrientedXPrecision,
+                              mOrientedYPrecision, xCursorPosition, yCursorPosition,
+                              mPointerSimple.downTime, /* videoFrames */ {});
+        getListener()->notifyMotion(&args);
     }
 
     if (hovering) {
@@ -3500,24 +3504,25 @@
             mPointerSimple.hovering = true;
 
             // Send hover enter.
-            getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                       AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
-                                       mCurrentRawState.buttonState, MotionClassification::NONE,
-                                       AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                                       &mPointerSimple.currentProperties,
-                                       &mPointerSimple.currentCoords, mOrientedXPrecision,
-                                       mOrientedYPrecision, xCursorPosition, yCursorPosition,
-                                       mPointerSimple.downTime, /* videoFrames */ {});
+            NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource,
+                                  displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0,
+                                  metaState, mCurrentRawState.buttonState,
+                                  MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                                  &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+                                  mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+                                  yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+            getListener()->notifyMotion(&args);
         }
 
         // Send hover move.
-        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                   AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
-                                   mCurrentRawState.buttonState, MotionClassification::NONE,
-                                   AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                                   &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
-                                   mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
-                                   yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+                              mCurrentRawState.buttonState, MotionClassification::NONE,
+                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
+                              &mPointerSimple.currentCoords, mOrientedXPrecision,
+                              mOrientedYPrecision, xCursorPosition, yCursorPosition,
+                              mPointerSimple.downTime, /* videoFrames */ {});
+        getListener()->notifyMotion(&args);
     }
 
     if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
@@ -3532,14 +3537,14 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
-        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
-                                   AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
-                                   mCurrentRawState.buttonState, MotionClassification::NONE,
-                                   AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                                   &mPointerSimple.currentProperties, &pointerCoords,
-                                   mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
-                                   yCursorPosition, mPointerSimple.downTime,
-                                   /* videoFrames */ {});
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
+                              mCurrentRawState.buttonState, MotionClassification::NONE,
+                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
+                              &pointerCoords, mOrientedXPrecision, mOrientedYPrecision,
+                              xCursorPosition, yCursorPosition, mPointerSimple.downTime,
+                              /* videoFrames */ {});
+        getListener()->notifyMotion(&args);
     }
 
     // Save state.
@@ -3610,11 +3615,12 @@
     std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
     std::for_each(frames.begin(), frames.end(),
                   [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
-    getContext()->notifyMotion(when, deviceId, source, displayId, policyFlags, action, actionButton,
-                               flags, metaState, buttonState, MotionClassification::NONE, edgeFlags,
-                               pointerCount, pointerProperties, pointerCoords, xPrecision,
-                               yPrecision, xCursorPosition, yCursorPosition, downTime,
-                               std::move(frames));
+    NotifyMotionArgs args(getContext()->getNextId(), when, deviceId, source, displayId, policyFlags,
+                          action, actionButton, flags, metaState, buttonState,
+                          MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
+                          pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
+                          downTime, std::move(frames));
+    getListener()->notifyMotion(&args);
 }
 
 bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties,
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
index 2e4ab45..3df6f36 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
@@ -53,7 +53,8 @@
     mIndex = -1;
 
     // Request InputReader to notify InputManagerService for vibration started.
-    getContext()->notifyVibratorState(systemTime(), getDeviceId(), true);
+    NotifyVibratorStateArgs args(getContext()->getNextId(), systemTime(), getDeviceId(), true);
+    getListener()->notifyVibratorState(&args);
     nextStep();
 }
 
@@ -131,7 +132,8 @@
     getDeviceContext().cancelVibrate();
 
     // Request InputReader to notify InputManagerService for vibration complete.
-    getContext()->notifyVibratorState(systemTime(), getDeviceId(), false);
+    NotifyVibratorStateArgs args(getContext()->getNextId(), systemTime(), getDeviceId(), false);
+    getListener()->notifyVibratorState(&args);
 }
 
 void VibratorInputMapper::dump(std::string& dump) {
diff --git a/services/inputflinger/reporter/Android.bp b/services/inputflinger/reporter/Android.bp
index fbc51da..7430731 100644
--- a/services/inputflinger/reporter/Android.bp
+++ b/services/inputflinger/reporter/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_headers {
     name: "libinputreporter_headers",
     export_include_dirs: ["."],
@@ -46,4 +55,3 @@
         "libinputreporter_headers",
     ],
 }
-
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 959dadc..42b54c7 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "inputflinger_tests",
     defaults: [
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 01945db..209639c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -31,6 +31,7 @@
 using android::base::StringPrintf;
 using android::os::InputEventInjectionResult;
 using android::os::InputEventInjectionSync;
+using android::os::TouchOcclusionMode;
 using namespace android::flag_operators;
 
 namespace android::inputdispatcher {
@@ -727,8 +728,9 @@
         ASSERT_EQ(OK, status) << mName.c_str() << ": consumer sendFinishedSignal should return OK.";
     }
 
-    void consumeEvent(int32_t expectedEventType, int32_t expectedAction, int32_t expectedDisplayId,
-                      int32_t expectedFlags) {
+    void consumeEvent(int32_t expectedEventType, int32_t expectedAction,
+                      std::optional<int32_t> expectedDisplayId,
+                      std::optional<int32_t> expectedFlags) {
         InputEvent* event = consume();
 
         ASSERT_NE(nullptr, event) << mName.c_str()
@@ -737,19 +739,25 @@
                 << mName.c_str() << " expected " << inputEventTypeToString(expectedEventType)
                 << " event, got " << inputEventTypeToString(event->getType()) << " event";
 
-        EXPECT_EQ(expectedDisplayId, event->getDisplayId());
+        if (expectedDisplayId.has_value()) {
+            EXPECT_EQ(expectedDisplayId, event->getDisplayId());
+        }
 
         switch (expectedEventType) {
             case AINPUT_EVENT_TYPE_KEY: {
                 const KeyEvent& keyEvent = static_cast<const KeyEvent&>(*event);
                 EXPECT_EQ(expectedAction, keyEvent.getAction());
-                EXPECT_EQ(expectedFlags, keyEvent.getFlags());
+                if (expectedFlags.has_value()) {
+                    EXPECT_EQ(expectedFlags.value(), keyEvent.getFlags());
+                }
                 break;
             }
             case AINPUT_EVENT_TYPE_MOTION: {
                 const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event);
                 EXPECT_EQ(expectedAction, motionEvent.getAction());
-                EXPECT_EQ(expectedFlags, motionEvent.getFlags());
+                if (expectedFlags.has_value()) {
+                    EXPECT_EQ(expectedFlags.value(), motionEvent.getFlags());
+                }
                 break;
             }
             case AINPUT_EVENT_TYPE_FOCUS: {
@@ -854,6 +862,7 @@
         mInfo.name = name;
         mInfo.type = InputWindowInfo::Type::APPLICATION;
         mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
+        mInfo.alpha = 1.0;
         mInfo.frameLeft = 0;
         mInfo.frameTop = 0;
         mInfo.frameRight = WIDTH;
@@ -883,6 +892,12 @@
 
     void setPaused(bool paused) { mInfo.paused = paused; }
 
+    void setAlpha(float alpha) { mInfo.alpha = alpha; }
+
+    void setTouchOcclusionMode(android::os::TouchOcclusionMode mode) {
+        mInfo.touchOcclusionMode = mode;
+    }
+
     void setFrame(const Rect& frame) {
         mInfo.frameLeft = frame.left;
         mInfo.frameTop = frame.top;
@@ -928,6 +943,11 @@
 
     void consumeMotionDown(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
                            int32_t expectedFlags = 0) {
+        consumeAnyMotionDown(expectedDisplayId, expectedFlags);
+    }
+
+    void consumeAnyMotionDown(std::optional<int32_t> expectedDisplayId = std::nullopt,
+                              std::optional<int32_t> expectedFlags = std::nullopt) {
         consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN, expectedDisplayId,
                      expectedFlags);
     }
@@ -971,8 +991,9 @@
         mInputReceiver->consumeCaptureEvent(hasCapture);
     }
 
-    void consumeEvent(int32_t expectedEventType, int32_t expectedAction, int32_t expectedDisplayId,
-                      int32_t expectedFlags) {
+    void consumeEvent(int32_t expectedEventType, int32_t expectedAction,
+                      std::optional<int32_t> expectedDisplayId,
+                      std::optional<int32_t> expectedFlags) {
         ASSERT_NE(mInputReceiver, nullptr) << "Invalid consume event on window with no receiver";
         mInputReceiver->consumeEvent(expectedEventType, expectedAction, expectedDisplayId,
                                      expectedFlags);
@@ -4240,4 +4261,264 @@
     mSecondWindow->consumeCaptureEvent(true);
 }
 
+class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
+protected:
+    constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
+    static const int32_t TOUCHED_APP_UID = 10001;
+    static const int32_t APP_B_UID = 10002;
+    static const int32_t APP_C_UID = 10003;
+
+    sp<FakeWindowHandle> mTouchWindow;
+
+    virtual void SetUp() override {
+        InputDispatcherTest::SetUp();
+        mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched");
+        mDispatcher->setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode::BLOCK);
+        mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY);
+    }
+
+    virtual void TearDown() override {
+        InputDispatcherTest::TearDown();
+        mTouchWindow.clear();
+    }
+
+    sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name,
+                                            os::TouchOcclusionMode mode, float alpha = 1.0f) {
+        sp<FakeWindowHandle> window = getWindow(uid, name);
+        window->setFlags(InputWindowInfo::Flag::NOT_TOUCHABLE);
+        window->setTouchOcclusionMode(mode);
+        window->setAlpha(alpha);
+        return window;
+    }
+
+    sp<FakeWindowHandle> getWindow(int32_t uid, std::string name) {
+        std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
+        sp<FakeWindowHandle> window =
+                new FakeWindowHandle(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
+        // Generate an arbitrary PID based on the UID
+        window->setOwnerInfo(1777 + (uid % 10000), uid);
+        return window;
+    }
+
+    void touch(const std::vector<PointF>& points = {PointF{100, 200}}) {
+        NotifyMotionArgs args =
+                generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                                   ADISPLAY_ID_DEFAULT, points);
+        mDispatcher->notifyMotion(&args);
+    }
+};
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
+    const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
+    w->setFrame(Rect(0, 0, 50, 50));
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch({PointF{100, 100}});
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY,
+                               MAXIMUM_OBSCURING_OPACITY);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_BlocksTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.9f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThreshold_BlocksTouch) {
+    // Resulting opacity = 1 - (1 - 0.7)*(1 - 0.7) = .91
+    const sp<FakeWindowHandle>& w1 =
+            getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    const sp<FakeWindowHandle>& w2 =
+            getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w1, w2, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThreshold_AllowsTouch) {
+    // Resulting opacity = 1 - (1 - 0.5)*(1 - 0.5) = .75
+    const sp<FakeWindowHandle>& w1 =
+            getOccludingWindow(APP_B_UID, "B1", TouchOcclusionMode::USE_OPACITY, 0.5f);
+    const sp<FakeWindowHandle>& w2 =
+            getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY, 0.5f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w1, w2, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
+       WindowsFromDifferentAppsEachBelowThreshold_AllowsTouch) {
+    const sp<FakeWindowHandle>& wB =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    const sp<FakeWindowHandle>& wC =
+            getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wB, wC, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThreshold_BlocksTouch) {
+    const sp<FakeWindowHandle>& wB =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    const sp<FakeWindowHandle>& wC =
+            getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, 0.9f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wB, wC, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
+       WindowWithOpacityAboveThresholdAndSelfWindow_BlocksTouch) {
+    const sp<FakeWindowHandle>& wA =
+            getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    const sp<FakeWindowHandle>& wB =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.9f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wA, wB, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
+       WindowWithOpacityBelowThresholdAndSelfWindow_AllowsTouch) {
+    const sp<FakeWindowHandle>& wA =
+            getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, 0.9f);
+    const sp<FakeWindowHandle>& wB =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wA, wB, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, 0.9f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
+       OpacityThresholdIs0AndWindowAboveThreshold_BlocksTouch) {
+    mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThreshold_AllowsTouch) {
+    mDispatcher->setMaximumObscuringOpacityForTouch(0.0f);
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest,
+       OpacityThresholdIs1AndWindowBelowThreshold_AllowsTouch) {
+    mDispatcher->setMaximumObscuringOpacityForTouch(1.0f);
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.9f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    mTouchWindow->consumeAnyMotionDown();
+}
+
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index bea9932..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 {
diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp
index 68f4f28..1d3e5b5 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libpowermanager",
 
diff --git a/services/schedulerservice/Android.bp b/services/schedulerservice/Android.bp
index 73802db..4ef72d0 100644
--- a/services/schedulerservice/Android.bp
+++ b/services/schedulerservice/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libschedulerservicehidl",
     srcs: [
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 532a2e5..ca9ff7c 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 subdirs = [
     "hidl"
 ]
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 2810bff..23893ea 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -914,6 +914,21 @@
     return mActivationCount.valueAt(activationIndex).numActiveClients() > 0;
 }
 
+void SensorDevice::onMicSensorAccessChanged(void* ident, int handle, nsecs_t samplingPeriodNs) {
+    Mutex::Autolock _l(mLock);
+    ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+    if (activationIndex < 0) {
+        ALOGW("Handle %d cannot be found in activation record", handle);
+        return;
+    }
+    Info& info(mActivationCount.editValueAt(activationIndex));
+    if (info.hasBatchParamsForIdent(ident)) {
+        ssize_t index = info.batchParams.indexOfKey(ident);
+        BatchParams& params = info.batchParams.editValueAt(index);
+        params.mTSample = samplingPeriodNs;
+    }
+}
+
 void SensorDevice::enableAllSensors() {
     if (mSensors == nullptr) return;
     Mutex::Autolock _l(mLock);
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 5e7d3da..75da7bb 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -125,6 +125,10 @@
 
     bool isSensorActive(int handle) const;
 
+    // To update the BatchParams of a SensorEventConnection when the mic toggle changes its state
+    // while the Sensors Off toggle is on.
+    void onMicSensorAccessChanged(void* ident, int handle, nsecs_t samplingPeriodNs);
+
     // Dumpable
     virtual std::string dump() const override;
     virtual void dump(util::ProtoOutputStream* proto) const override;
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index e4c33da..af86d09 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -32,6 +32,8 @@
         : mService(service), mUid(uid), mMem(*mem),
         mHalChannelHandle(halChannelHandle),
         mOpPackageName(opPackageName), mDestroyed(false) {
+    mIsRateCappedBasedOnPermission = mService->isRateCappedBasedOnPermission(mOpPackageName);
+    mUserId = multiuser_get_user_id(mUid);
     ALOGD_IF(DEBUG_CONNECTIONS, "Created SensorDirectConnection");
 }
 
@@ -101,6 +103,14 @@
     }
 }
 
+void SensorService::SensorDirectConnection::onMicSensorAccessChanged(bool isMicToggleOn) {
+    if (isMicToggleOn) {
+        capRates();
+    } else {
+        uncapRates();
+    }
+}
+
 bool SensorService::SensorDirectConnection::hasSensorAccess() const {
     return mService->hasSensorAccess(mUid, mOpPackageName);
 }
@@ -134,6 +144,7 @@
 
     if (handle == -1 && rateLevel == SENSOR_DIRECT_RATE_STOP) {
         stopAll();
+        mMicRateBackup.clear();
         return NO_ERROR;
     }
 
@@ -157,6 +168,14 @@
         return INVALID_OPERATION;
     }
 
+    int requestedRateLevel = rateLevel;
+    if (mService->isSensorInCappedSet(s.getType()) && rateLevel != SENSOR_DIRECT_RATE_STOP) {
+        status_t err = mService->adjustRateLevelBasedOnMicAndPermission(&rateLevel, mOpPackageName);
+        if (err != OK) {
+            return err;
+        }
+    }
+
     struct sensors_direct_cfg_t config = {
         .rate_level = rateLevel
     };
@@ -168,18 +187,100 @@
     if (rateLevel == SENSOR_DIRECT_RATE_STOP) {
         if (ret == NO_ERROR) {
             mActivated.erase(handle);
+            mMicRateBackup.erase(handle);
         } else if (ret > 0) {
             ret = UNKNOWN_ERROR;
         }
     } else {
         if (ret > 0) {
             mActivated[handle] = rateLevel;
+            if (mService->isSensorInCappedSet(s.getType())) {
+                // Back up the rates that the app is allowed to have if the mic toggle is off
+                // This is used in the uncapRates() function.
+                if (!mIsRateCappedBasedOnPermission ||
+                            requestedRateLevel <= SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
+                    mMicRateBackup[handle] = requestedRateLevel;
+                } else {
+                    mMicRateBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+                }
+            }
         }
     }
 
     return ret;
 }
 
+void SensorService::SensorDirectConnection::capRates() {
+    Mutex::Autolock _l(mConnectionLock);
+    const struct sensors_direct_cfg_t capConfig = {
+        .rate_level = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL
+    };
+
+    const struct sensors_direct_cfg_t stopConfig = {
+        .rate_level = SENSOR_DIRECT_RATE_STOP
+    };
+
+    // If our requests are in the backup, then we shouldn't activate sensors from here
+    bool temporarilyStopped = mActivated.empty() && !mActivatedBackup.empty();
+    std::unordered_map<int, int>& existingConnections =
+                    (!temporarilyStopped) ? mActivated : mActivatedBackup;
+
+    SensorDevice& dev(SensorDevice::getInstance());
+    for (auto &i : existingConnections) {
+        int handle = i.first;
+        int rateLevel = i.second;
+        sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+        if (si != nullptr) {
+            const Sensor& s = si->getSensor();
+            if (mService->isSensorInCappedSet(s.getType()) &&
+                        rateLevel > SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
+                mMicRateBackup[handle] = rateLevel;
+                // Modify the rate kept by the existing map
+                existingConnections[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+                // Only reconfigure the channel if it's ongoing
+                if (!temporarilyStopped) {
+                    // Stopping before reconfiguring is the well-tested path in CTS
+                    dev.configureDirectChannel(handle, getHalChannelHandle(), &stopConfig);
+                    dev.configureDirectChannel(handle, getHalChannelHandle(), &capConfig);
+                }
+            }
+        }
+    }
+}
+
+void SensorService::SensorDirectConnection::uncapRates() {
+    Mutex::Autolock _l(mConnectionLock);
+
+    // If our requests are in the backup, then we shouldn't activate sensors from here
+    bool temporarilyStopped = mActivated.empty() && !mActivatedBackup.empty();
+    std::unordered_map<int, int>& existingConnections =
+                    (!temporarilyStopped) ? mActivated : mActivatedBackup;
+
+    const struct sensors_direct_cfg_t stopConfig = {
+        .rate_level = SENSOR_DIRECT_RATE_STOP
+    };
+    SensorDevice& dev(SensorDevice::getInstance());
+    for (auto &i : mMicRateBackup) {
+        int handle = i.first;
+        int rateLevel = i.second;
+
+        const struct sensors_direct_cfg_t config = {
+            .rate_level = rateLevel
+        };
+
+        // Modify the rate kept by the existing map
+        existingConnections[handle] = rateLevel;
+
+        // Only reconfigure the channel if it's ongoing
+        if (!temporarilyStopped) {
+            // Stopping before reconfiguring is the well-tested path in CTS
+            dev.configureDirectChannel(handle, getHalChannelHandle(), &stopConfig);
+            dev.configureDirectChannel(handle, getHalChannelHandle(), &config);
+        }
+    }
+    mMicRateBackup.clear();
+}
+
 void SensorService::SensorDirectConnection::stopAll(bool backupRecord) {
     Mutex::Autolock _l(mConnectionLock);
     stopAllLocked(backupRecord);
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index 4181b65..a3f348b 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -50,6 +50,8 @@
     // regained due to changes in the sensor restricted/privacy mode or the
     // app changed to idle/active status.
     void onSensorAccessChanged(bool hasAccess);
+    void onMicSensorAccessChanged(bool isMicToggleOn);
+    userid_t getUserId() const { return mUserId; }
 
 protected:
     virtual ~SensorDirectConnection();
@@ -82,6 +84,11 @@
     // If no requests are backed up by stopAll(), this method is no-op.
     void recoverAll();
 
+    // Limits all active sensor direct report requests when the mic toggle is flipped to on.
+    void capRates();
+    // Recover sensor requests previously capped by capRates().
+    void uncapRates();
+
     const sp<SensorService> mService;
     const uid_t mUid;
     const sensors_direct_mem_t mMem;
@@ -91,9 +98,12 @@
     mutable Mutex mConnectionLock;
     std::unordered_map<int, int> mActivated;
     std::unordered_map<int, int> mActivatedBackup;
+    std::unordered_map<int, int> mMicRateBackup;
 
+    std::atomic_bool mIsRateCappedBasedOnPermission;
     mutable Mutex mDestroyLock;
     bool mDestroyed;
+    userid_t mUserId;
 };
 
 } // namepsace android
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 6810c1b7..5225dd7 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -38,12 +38,14 @@
 
 SensorService::SensorEventConnection::SensorEventConnection(
         const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
-        const String16& opPackageName)
+        const String16& opPackageName, const String16& attributionTag)
     : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
       mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(nullptr),
       mCacheSize(0), mMaxCacheSize(0), mTimeOfLastEventDrop(0), mEventsDropped(0),
-      mPackageName(packageName), mOpPackageName(opPackageName), mTargetSdk(kTargetSdkUnknown),
-      mDestroyed(false) {
+      mPackageName(packageName), mOpPackageName(opPackageName), mAttributionTag(attributionTag),
+      mTargetSdk(kTargetSdkUnknown), mDestroyed(false) {
+    mIsRateCappedBasedOnPermission = mService->isRateCappedBasedOnPermission(mOpPackageName);
+    mUserId = multiuser_get_user_id(mUid);
     mChannel = new BitTube(mService->mSocketBufferSize);
 #if DEBUG_CONNECTIONS
     mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -285,6 +287,29 @@
     }
 }
 
+// TODO(b/179649922): A better algorithm to guarantee that capped connections will get a sampling
+// rate close to 200 Hz. With the current algorithm, apps might be punished unfairly: E.g.,two apps
+// make requests to the sensor service at the same time, one is not capped and uses 250 Hz, and one
+//is capped, the capped connection will only get 125 Hz.
+void SensorService::SensorEventConnection::addSensorEventsToBuffer(bool shouldResample,
+    const sensors_event_t& sensorEvent, sensors_event_t* buffer, int* index) {
+    if (!shouldResample || !mService->isSensorInCappedSet(sensorEvent.type)) {
+        buffer[(*index)++] = sensorEvent;
+    } else {
+        int64_t lastTimestamp = -1;
+        auto entry = mSensorLastTimestamp.find(sensorEvent.sensor);
+        if (entry != mSensorLastTimestamp.end()) {
+            lastTimestamp = entry->second;
+        }
+        // Allow 10% headroom here because the clocks are not perfect.
+        if (lastTimestamp == -1  || sensorEvent.timestamp - lastTimestamp
+                                        >= 0.9 * SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+            mSensorLastTimestamp[sensorEvent.sensor] = sensorEvent.timestamp;
+            buffer[(*index)++] = sensorEvent;
+        }
+    }
+}
+
 status_t SensorService::SensorEventConnection::sendEvents(
         sensors_event_t const* buffer, size_t numEvents,
         sensors_event_t* scratch,
@@ -293,6 +318,8 @@
 
     std::unique_ptr<sensors_event_t[]> sanitizedBuffer;
 
+    bool shouldResample = mService->isMicSensorPrivacyEnabledForUid(mUid) ||
+                            mIsRateCappedBasedOnPermission;
     int count = 0;
     Mutex::Autolock _l(mConnectionLock);
     if (scratch) {
@@ -346,7 +373,7 @@
                     // Regular sensor event, just copy it to the scratch buffer after checking
                     // the AppOp.
                     if (hasSensorAccess() && noteOpIfRequired(buffer[i])) {
-                        scratch[count++] = buffer[i];
+                        addSensorEventsToBuffer(shouldResample, buffer[i], scratch, &count);
                     }
                 }
                 i++;
@@ -356,12 +383,13 @@
                                         buffer[i].meta_data.sensor == sensor_handle)));
         }
     } else {
+        sanitizedBuffer.reset(new sensors_event_t[numEvents]);
+        scratch = sanitizedBuffer.get();
         if (hasSensorAccess()) {
-            scratch = const_cast<sensors_event_t *>(buffer);
-            count = numEvents;
+            for (size_t i = 0; i < numEvents; i++) {
+                addSensorEventsToBuffer(shouldResample, buffer[i], scratch, &count);
+            }
         } else {
-            sanitizedBuffer.reset(new sensors_event_t[numEvents]);
-            scratch = sanitizedBuffer.get();
             for (size_t i = 0; i < numEvents; i++) {
                 if (buffer[i].type == SENSOR_TYPE_META_DATA) {
                     scratch[count++] = buffer[i++];
@@ -465,7 +493,8 @@
             noteMsg.append(String16(mService->getSensorStringType(sensorHandle)));
             noteMsg.append(String16(")"));
             int32_t appOpMode = mService->sAppOpsManager.noteOp(iter->second, mUid,
-                                                                mOpPackageName, {}, noteMsg);
+                                                                mOpPackageName, mAttributionTag,
+                                                                noteMsg);
             success = (appOpMode == AppOpsManager::MODE_ALLOWED);
         }
     }
@@ -684,24 +713,118 @@
 
     status_t err;
     if (enabled) {
+        nsecs_t requestedSamplingPeriodNs = samplingPeriodNs;
+        bool isSensorCapped = false;
+        sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+        if (si != nullptr) {
+            const Sensor& s = si->getSensor();
+            if (mService->isSensorInCappedSet(s.getType())) {
+                isSensorCapped = true;
+            }
+        }
+        if (isSensorCapped) {
+            err = mService->adjustSamplingPeriodBasedOnMicAndPermission(&samplingPeriodNs,
+                                String16(mOpPackageName));
+            if (err != OK) {
+                return err;
+            }
+        }
         err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
                                reservedFlags, mOpPackageName);
+        if (err == OK && isSensorCapped) {
+            if (!mIsRateCappedBasedOnPermission ||
+                        requestedSamplingPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+                mMicSamplingPeriodBackup[handle] = requestedSamplingPeriodNs;
+            } else {
+                mMicSamplingPeriodBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+            }
+        }
 
     } else {
         err = mService->disable(this, handle);
+        mMicSamplingPeriodBackup.erase(handle);
     }
     return err;
 }
 
-status_t SensorService::SensorEventConnection::setEventRate(
-        int handle, nsecs_t samplingPeriodNs)
-{
+status_t SensorService::SensorEventConnection::setEventRate(int handle, nsecs_t samplingPeriodNs) {
     if (mDestroyed) {
         android_errorWriteLog(0x534e4554, "168211968");
         return DEAD_OBJECT;
     }
 
-    return mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
+    nsecs_t requestedSamplingPeriodNs = samplingPeriodNs;
+    bool isSensorCapped = false;
+    sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+    if (si != nullptr) {
+        const Sensor& s = si->getSensor();
+        if (mService->isSensorInCappedSet(s.getType())) {
+            isSensorCapped = true;
+        }
+    }
+    if (isSensorCapped) {
+        status_t err = mService->adjustSamplingPeriodBasedOnMicAndPermission(&samplingPeriodNs,
+                            String16(mOpPackageName));
+        if (err != OK) {
+            return err;
+        }
+    }
+    status_t ret = mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
+    if (ret == OK && isSensorCapped) {
+        if (!mIsRateCappedBasedOnPermission ||
+                    requestedSamplingPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+            mMicSamplingPeriodBackup[handle] = requestedSamplingPeriodNs;
+        } else {
+            mMicSamplingPeriodBackup[handle] = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+        }
+    }
+    return ret;
+}
+
+void SensorService::SensorEventConnection::onMicSensorAccessChanged(bool isMicToggleOn) {
+    if (isMicToggleOn) {
+        capRates();
+    } else {
+        uncapRates();
+    }
+}
+
+void SensorService::SensorEventConnection::capRates() {
+    Mutex::Autolock _l(mConnectionLock);
+    SensorDevice& dev(SensorDevice::getInstance());
+    for (auto &i : mMicSamplingPeriodBackup) {
+        int handle = i.first;
+        nsecs_t samplingPeriodNs = i.second;
+        if (samplingPeriodNs < SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+            if (hasSensorAccess()) {
+                mService->setEventRate(this, handle, SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS,
+                                       mOpPackageName);
+            } else {
+                // Update SensorDevice with the capped rate so that when sensor access is restored,
+                // the correct event rate is used.
+                dev.onMicSensorAccessChanged(this, handle,
+                                             SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS);
+            }
+        }
+    }
+}
+
+void SensorService::SensorEventConnection::uncapRates() {
+    Mutex::Autolock _l(mConnectionLock);
+    SensorDevice& dev(SensorDevice::getInstance());
+    for (auto &i : mMicSamplingPeriodBackup) {
+        int handle = i.first;
+        nsecs_t samplingPeriodNs = i.second;
+        if (samplingPeriodNs < SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+            if (hasSensorAccess()) {
+                mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
+            } else {
+                // Update SensorDevice with the uncapped rate so that when sensor access is
+                // restored, the correct event rate is used.
+                dev.onMicSensorAccessChanged(this, handle, samplingPeriodNs);
+            }
+        }
+    }
 }
 
 status_t  SensorService::SensorEventConnection::flush() {
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 9487a39..4e3f120 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -50,7 +50,8 @@
 
 public:
     SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName,
-                          bool isDataInjectionMode, const String16& opPackageName);
+                          bool isDataInjectionMode, const String16& opPackageName,
+                          const String16& attributionTag);
 
     status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch,
                         wp<const SensorEventConnection> const * mapFlushEventsToConnections = nullptr);
@@ -68,6 +69,9 @@
     String8 getPackageName() const;
 
     uid_t getUid() const { return mUid; }
+    // cap/uncap existing connection depending on the state of the mic toggle.
+    void onMicSensorAccessChanged(bool isMicToggleOn);
+    userid_t getUserId() const { return mUserId; }
 
 private:
     virtual ~SensorEventConnection();
@@ -137,10 +141,20 @@
 
     // Call noteOp for the sensor if the sensor requires a permission
     bool noteOpIfRequired(const sensors_event_t& event);
+    // Limits all active connections when the mic toggle is flipped to on.
+    void capRates();
+    // Recover sensor connection previously capped by capRates().
+    void uncapRates();
 
+    // Add sensorEvent to buffer at position index if the sensorEvent satisfies throttling rules.
+    void addSensorEventsToBuffer(bool shouldResample, const sensors_event_t& sensorEvent,
+                        sensors_event_t* buffer, int* index);
     sp<SensorService> const mService;
     sp<BitTube> mChannel;
     uid_t mUid;
+    std::atomic_bool mIsRateCappedBasedOnPermission;
+    // Store a mapping of sensor to the timestamp of their last sensor event.
+    std::unordered_map<int, int64_t> mSensorLastTimestamp;
     mutable Mutex mConnectionLock;
     // Number of events from wake up sensors which are still pending and haven't been delivered to
     // the corresponding application. It is incremented by one unit for each write to the socket.
@@ -177,6 +191,7 @@
     int mEventsDropped;
     String8 mPackageName;
     const String16 mOpPackageName;
+    const String16 mAttributionTag;
     int mTargetSdk;
 #if DEBUG_CONNECTIONS
     int mEventsReceived, mEventsSent, mEventsSentFromCache;
@@ -189,6 +204,9 @@
     // Store a mapping of sensor handles to required AppOp for a sensor. This map only contains a
     // valid mapping for sensors that require a permission in order to reduce the lookup time.
     std::unordered_map<int32_t, int32_t> mHandleToAppOp;
+    // Mapping of sensor handles to its rate before being capped by the mic toggle.
+    std::unordered_map<int, nsecs_t> mMicSamplingPeriodBackup;
+    userid_t mUserId;
 };
 
 } // namepsace android
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 8f25bdb..942b7ae 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <android-base/strings.h>
 #include <android/content/pm/IPackageManagerNative.h>
 #include <android/util/ProtoOutputStream.h>
 #include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
@@ -88,6 +89,8 @@
 #define SENSOR_SERVICE_SCHED_FIFO_PRIORITY 10
 
 // Permissions.
+static const String16 sAccessHighSensorSamplingRatePermission(
+        "android.permission.HIGH_SAMPLING_RATE_SENSORS");
 static const String16 sDumpPermission("android.permission.DUMP");
 static const String16 sLocationHardwarePermission("android.permission.LOCATION_HARDWARE");
 static const String16 sManageSensorsPermission("android.permission.MANAGE_SENSORS");
@@ -366,6 +369,9 @@
     }
     mUidPolicy->unregisterSelf();
     mSensorPrivacyPolicy->unregisterSelf();
+    for (auto const& [userId, policy] : mMicSensorPrivacyPolicies) {
+        policy->unregisterSelf();
+    }
 }
 
 status_t SensorService::dump(int fd, const Vector<String16>& args) {
@@ -695,6 +701,35 @@
     }
 }
 
+void SensorService::capRates(userid_t userId) {
+    ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+    for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
+        if (conn->getUserId() == userId) {
+            conn->onMicSensorAccessChanged(true);
+        }
+    }
+
+    for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
+        if (conn->getUserId() == userId) {
+            conn->onMicSensorAccessChanged(true);
+        }
+    }
+}
+
+void SensorService::uncapRates(userid_t userId) {
+    ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+    for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
+        if (conn->getUserId() == userId) {
+            conn->onMicSensorAccessChanged(false);
+        }
+    }
+
+    for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
+        if (conn->getUserId() == userId) {
+            conn->onMicSensorAccessChanged(false);
+        }
+    }
+}
 
 // NOTE: This is a remote API - make sure all args are validated
 status_t SensorService::shellCommand(int in, int out, int err, Vector<String16>& args) {
@@ -1209,14 +1244,20 @@
     }
 }
 
-Vector<Sensor> SensorService::getSensorList(const String16& /* opPackageName */) {
+Vector<Sensor> SensorService::getSensorList(const String16& opPackageName) {
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.sensors", value, "0");
     const Vector<Sensor>& initialSensorList = (atoi(value)) ?
             mSensors.getUserDebugSensors() : mSensors.getUserSensors();
     Vector<Sensor> accessibleSensorList;
+
+    bool isCapped = isRateCappedBasedOnPermission(opPackageName);
     for (size_t i = 0; i < initialSensorList.size(); i++) {
         Sensor sensor = initialSensorList[i];
+        if (isCapped && isSensorInCappedSet(sensor.getType())) {
+            sensor.capMinDelayMicros(SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS / 1000);
+            sensor.capHighestDirectReportRateLevel(SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL);
+        }
         accessibleSensorList.add(sensor);
     }
     makeUuidsIntoIdsForSensorList(accessibleSensorList);
@@ -1244,7 +1285,7 @@
 }
 
 sp<ISensorEventConnection> SensorService::createSensorEventConnection(const String8& packageName,
-        int requestedMode, const String16& opPackageName) {
+        int requestedMode, const String16& opPackageName, const String16& attributionTag) {
     // Only 2 modes supported for a SensorEventConnection ... NORMAL and DATA_INJECTION.
     if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) {
         return nullptr;
@@ -1266,7 +1307,7 @@
     String16 connOpPackageName =
             (opPackageName == String16("")) ? String16(connPackageName) : opPackageName;
     sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName,
-            requestedMode == DATA_INJECTION, connOpPackageName));
+            requestedMode == DATA_INJECTION, connOpPackageName, attributionTag));
     if (requestedMode == DATA_INJECTION) {
         mConnectionHolder.addEventConnectionIfNotPresent(result);
         // Add the associated file descriptor to the Looper for polling whenever there is data to
@@ -2024,6 +2065,69 @@
     return mUidPolicy->isUidActive(uid);
 }
 
+bool SensorService::isRateCappedBasedOnPermission(const String16& opPackageName) {
+    int targetSdk = getTargetSdkVersion(opPackageName);
+    bool hasSamplingRatePermission = PermissionCache::checkCallingPermission(
+                    sAccessHighSensorSamplingRatePermission);
+    if (targetSdk < __ANDROID_API_S__ ||
+            (targetSdk >= __ANDROID_API_S__ && hasSamplingRatePermission)) {
+        return false;
+    }
+    return true;
+}
+
+bool SensorService::isSensorInCappedSet(int sensorType) {
+    return (sensorType == SENSOR_TYPE_ACCELEROMETER
+            || sensorType == SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED
+            || sensorType == SENSOR_TYPE_GYROSCOPE
+            || sensorType == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED
+            || sensorType == SENSOR_TYPE_MAGNETIC_FIELD
+            || sensorType == SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED);
+}
+
+status_t SensorService::adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* requestedPeriodNs,
+        const String16& opPackageName) {
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    bool shouldCapBasedOnPermission = isRateCappedBasedOnPermission(opPackageName);
+    if (*requestedPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+        return OK;
+    }
+    if (shouldCapBasedOnPermission) {
+        *requestedPeriodNs = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+        if (isPackageDebuggable(opPackageName)) {
+            return PERMISSION_DENIED;
+        }
+        return OK;
+    }
+    if (isMicSensorPrivacyEnabledForUid(uid)) {
+        *requestedPeriodNs = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+        return OK;
+    }
+    return OK;
+}
+
+status_t SensorService::adjustRateLevelBasedOnMicAndPermission(int* requestedRateLevel,
+        const String16& opPackageName) {
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    bool shouldCapBasedOnPermission = isRateCappedBasedOnPermission(opPackageName);
+
+    if (*requestedRateLevel <= SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
+        return OK;
+    }
+    if (shouldCapBasedOnPermission) {
+        *requestedRateLevel = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+        if (isPackageDebuggable(opPackageName)) {
+            return PERMISSION_DENIED;
+        }
+        return OK;
+    }
+    if (isMicSensorPrivacyEnabledForUid(uid)) {
+        *requestedRateLevel = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+        return OK;
+    }
+    return OK;
+}
+
 void SensorService::SensorPrivacyPolicy::registerSelf() {
     SensorPrivacyManager spm;
     mSensorPrivacyEnabled = spm.isSensorPrivacyEnabled();
@@ -2042,16 +2146,56 @@
 binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(bool enabled) {
     mSensorPrivacyEnabled = enabled;
     sp<SensorService> service = mService.promote();
+
     if (service != nullptr) {
-        if (enabled) {
-            service->disableAllSensors();
+        if (mIsIndividualMic) {
+            if (enabled) {
+                service->capRates(mUserId);
+            } else {
+                service->uncapRates(mUserId);
+            }
         } else {
-            service->enableAllSensors();
+            if (enabled) {
+                service->disableAllSensors();
+            } else {
+                service->enableAllSensors();
+            }
         }
     }
     return binder::Status::ok();
 }
 
+status_t SensorService::SensorPrivacyPolicy::registerSelfForIndividual(int userId) {
+    Mutex::Autolock _l(mSensorPrivacyLock);
+
+    SensorPrivacyManager spm;
+    status_t err = spm.addIndividualSensorPrivacyListener(userId,
+            SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE, this);
+
+    if (err != OK) {
+        ALOGE("Cannot register a mic listener.");
+        return err;
+    }
+    mSensorPrivacyEnabled = spm.isIndividualSensorPrivacyEnabled(userId,
+                SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE);
+
+    mIsIndividualMic = true;
+    mUserId = userId;
+    return OK;
+}
+
+bool SensorService::isMicSensorPrivacyEnabledForUid(uid_t uid) {
+    userid_t userId = multiuser_get_user_id(uid);
+    if (mMicSensorPrivacyPolicies.find(userId) == mMicSensorPrivacyPolicies.end()) {
+        sp<SensorPrivacyPolicy> userPolicy = new SensorPrivacyPolicy(this);
+        if (userPolicy->registerSelfForIndividual(userId) != OK) {
+            return false;
+        }
+        mMicSensorPrivacyPolicies[userId] = userPolicy;
+    }
+    return mMicSensorPrivacyPolicies[userId]->isSensorPrivacyEnabled();
+}
+
 SensorService::ConnectionSafeAutolock::ConnectionSafeAutolock(
         SensorService::SensorConnectionHolder& holder, Mutex& mutex)
         : mConnectionHolder(holder), mAutolock(mutex) {}
@@ -2109,4 +2253,17 @@
     return ConnectionSafeAutolock(*this, mutex);
 }
 
+bool SensorService::isPackageDebuggable(const String16& opPackageName) {
+    bool debugMode = false;
+    sp<IBinder> binder = defaultServiceManager()->getService(String16("package_native"));
+    if (binder != nullptr) {
+        sp<content::pm::IPackageManagerNative> packageManager =
+                interface_cast<content::pm::IPackageManagerNative>(binder);
+        if (packageManager != nullptr) {
+            binder::Status status = packageManager->isPackageDebuggable(
+                opPackageName, &debugMode);
+        }
+    }
+    return debugMode;
+}
 } // namespace android
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 50c7c2f..9c5060a 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -61,6 +61,15 @@
 
 #define SENSOR_REGISTRATIONS_BUF_SIZE 200
 
+// Apps that targets S+ and do not have HIGH_SAMPLING_RATE_SENSORS permission will be capped
+// at 200 Hz. The cap also applies to all requests when the mic toggle is flipped to on, regardless
+// of their target SDKs and permission.
+// Capped sampling periods for apps that have non-direct sensor connections.
+#define SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS (5 * 1000 * 1000)
+// Capped sampling rate level for apps that have direct sensor connections.
+// The enum SENSOR_DIRECT_RATE_NORMAL corresponds to a rate value of at most 110 Hz.
+#define SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL SENSOR_DIRECT_RATE_NORMAL
+
 namespace android {
 // ---------------------------------------------------------------------------
 class SensorInterface;
@@ -95,6 +104,8 @@
     status_t flushSensor(const sp<SensorEventConnection>& connection,
                          const String16& opPackageName);
 
+    // Returns true if a sensor should be throttled according to our rate-throttling rules.
+    static bool isSensorInCappedSet(int sensorType);
 
     virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);
 
@@ -212,17 +223,23 @@
     // connections will be allowed again.
     class SensorPrivacyPolicy : public hardware::BnSensorPrivacyListener {
         public:
-            explicit SensorPrivacyPolicy(wp<SensorService> service) : mService(service) {}
+            explicit SensorPrivacyPolicy(wp<SensorService> service)
+                    : mService(service), mIsIndividualMic(false), mUserId(0) {}
             void registerSelf();
             void unregisterSelf();
 
+            status_t registerSelfForIndividual(int userId);
+
             bool isSensorPrivacyEnabled();
 
             binder::Status onSensorPrivacyChanged(bool enabled);
 
         private:
             wp<SensorService> mService;
+            Mutex mSensorPrivacyLock;
             std::atomic_bool mSensorPrivacyEnabled;
+            bool mIsIndividualMic;
+            userid_t mUserId;
     };
 
     enum Mode {
@@ -286,7 +303,7 @@
     virtual Vector<Sensor> getDynamicSensorList(const String16& opPackageName);
     virtual sp<ISensorEventConnection> createSensorEventConnection(
             const String8& packageName,
-            int requestedMode, const String16& opPackageName);
+            int requestedMode, const String16& opPackageName, const String16& attributionTag);
     virtual int isDataInjectionEnabled();
     virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
             uint32_t size, int32_t type, int32_t format, const native_handle *resource);
@@ -346,6 +363,13 @@
     // whitelisted). mLock must be held to invoke this method.
     bool isOperationRestrictedLocked(const String16& opPackageName);
 
+    status_t adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* requestedPeriodNs,
+                                                    const String16& opPackageName);
+    status_t adjustRateLevelBasedOnMicAndPermission(int* requestedRateLevel,
+                                              const String16& opPackageName);
+    bool isRateCappedBasedOnPermission(const String16& opPackageName);
+    bool isPackageDebuggable(const String16& opPackageName);
+
     // Reset the state of SensorService to NORMAL mode.
     status_t resetToNormalMode();
     status_t resetToNormalModeLocked();
@@ -385,6 +409,11 @@
     void enableAllSensors();
     void enableAllSensorsLocked(ConnectionSafeAutolock* connLock);
 
+    // Caps active direct connections (when the mic toggle is flipped to on)
+    void capRates(userid_t userId);
+    // Removes the capped rate on active direct connections (when the mic toggle is flipped to off)
+    void uncapRates(userid_t userId);
+
     static uint8_t sHmacGlobalKey[128];
     static bool sHmacGlobalKeyIsValid;
 
@@ -426,6 +455,11 @@
     static std::map<String16, int> sPackageTargetVersion;
     static Mutex sPackageTargetVersionLock;
     static String16 sSensorInterfaceDescriptorPrefix;
+
+    // Map from user to SensorPrivacyPolicy
+    std::map<userid_t, sp<SensorPrivacyPolicy>> mMicSensorPrivacyPolicies;
+    // Checks if the mic sensor privacy is enabled for the uid
+    bool isMicSensorPrivacyEnabledForUid(uid_t uid);
 };
 
 } // namespace android
diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp
index 0e1af59..9bafb3c 100644
--- a/services/sensorservice/hidl/Android.bp
+++ b/services/sensorservice/hidl/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libsensorservicehidl",
     srcs: [
diff --git a/services/sensorservice/tests/Android.bp b/services/sensorservice/tests/Android.bp
index d33c0ca..ddc03a1 100644
--- a/services/sensorservice/tests/Android.bp
+++ b/services/sensorservice/tests/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "test-sensorservice",
     srcs: ["sensorservicetest.cpp"],
diff --git a/services/stats/Android.bp b/services/stats/Android.bp
index 1ce0524..a472c5f 100644
--- a/services/stats/Android.bp
+++ b/services/stats/Android.bp
@@ -1,11 +1,23 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libstatshidl",
     srcs: [
+        "StatsAidl.cpp",
         "StatsHal.cpp",
     ],
     cflags: ["-Wall", "-Werror"],
     shared_libs: [
         "android.frameworks.stats@1.0",
+        "android.frameworks.stats-V1-ndk_platform",
+        "libbinder_ndk",
         "libhidlbase",
         "liblog",
         "libstatslog",
@@ -13,7 +25,11 @@
         "libutils",
     ],
     export_include_dirs: [
-    	"include/",
+        "include/",
+    ],
+    export_shared_lib_headers: [
+        "android.frameworks.stats@1.0",
+        "android.frameworks.stats-V1-ndk_platform",
     ],
     local_include_dirs: [
         "include/stats",
diff --git a/services/stats/StatsAidl.cpp b/services/stats/StatsAidl.cpp
new file mode 100644
index 0000000..a3b68f1
--- /dev/null
+++ b/services/stats/StatsAidl.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#define LOG_TAG "StatsAidl"
+
+#include <log/log.h>
+#include <statslog.h>
+
+#include "StatsAidl.h"
+
+namespace aidl {
+namespace android {
+namespace frameworks {
+namespace stats {
+
+StatsHal::StatsHal() {}
+
+ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) {
+    std::string reverseDomainName = (std::string) vendorAtom.reverseDomainName;
+    if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
+        ALOGE("Atom ID %ld is not a valid vendor atom ID", (long) vendorAtom.atomId);
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+            -1, "Not a valid vendor atom ID");
+    }
+    if (reverseDomainName.length() > 50) {
+        ALOGE("Vendor atom reverse domain name %s is too long.", reverseDomainName.c_str());
+        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+            -1, "Vendor atom reverse domain name is too long");
+    }
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, vendorAtom.atomId);
+    AStatsEvent_writeString(event, vendorAtom.reverseDomainName.c_str());
+    for (const auto& atomValue : vendorAtom.values) {
+        switch (atomValue.getTag()) {
+            case VendorAtomValue::intValue:
+                AStatsEvent_writeInt32(event,
+                    atomValue.get<VendorAtomValue::intValue>());
+                break;
+            case VendorAtomValue::longValue:
+                AStatsEvent_writeInt64(event,
+                    atomValue.get<VendorAtomValue::longValue>());
+                break;
+            case VendorAtomValue::floatValue:
+                AStatsEvent_writeFloat(event,
+                    atomValue.get<VendorAtomValue::floatValue>());
+                break;
+            case VendorAtomValue::stringValue:
+                AStatsEvent_writeString(event,
+                    atomValue.get<VendorAtomValue::stringValue>().c_str());
+                break;
+        }
+    }
+    AStatsEvent_build(event);
+    const int ret = AStatsEvent_write(event);
+    AStatsEvent_release(event);
+
+    return ret <= 0 ?
+            ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(ret, "report atom failed") :
+            ndk::ScopedAStatus::ok();
+}
+
+}  // namespace stats
+}  // namespace frameworks
+}  // namespace android
+}  // namespace aidl
diff --git a/services/stats/android.frameworks.stats@1.0-service.xml b/services/stats/android.frameworks.stats@1.0-service.xml
index bb02f66..5fd361c 100644
--- a/services/stats/android.frameworks.stats@1.0-service.xml
+++ b/services/stats/android.frameworks.stats@1.0-service.xml
@@ -8,4 +8,10 @@
             <instance>default</instance>
         </interface>
     </hal>
+
+    <hal format="aidl">
+        <name>android.frameworks.stats</name>
+        <version>1</version>
+        <fqname>IStats/default</fqname>
+    </hal>
 </manifest>
diff --git a/services/stats/include/stats/StatsAidl.h b/services/stats/include/stats/StatsAidl.h
new file mode 100644
index 0000000..219e71e
--- /dev/null
+++ b/services/stats/include/stats/StatsAidl.h
@@ -0,0 +1,38 @@
+/*
+ * 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 <aidl/android/frameworks/stats/BnStats.h>
+
+namespace aidl {
+namespace android {
+namespace frameworks {
+namespace stats {
+
+class StatsHal : public BnStats {
+public:
+    StatsHal();
+
+    /**
+     * Binder call to get vendor atom.
+     */
+    virtual ndk::ScopedAStatus reportVendorAtom(
+        const VendorAtom& in_vendorAtom) override;
+};
+
+}  // namespace stats
+}  // namespace frameworks
+}  // namespace android
+}  // namespace aidl
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 8d1258a..625f315 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "surfaceflinger_defaults",
     cflags: [
@@ -106,6 +115,10 @@
         thin: true,
     },
     whole_program_vtables: true, // Requires ThinLTO
+    pgo: {
+        sampling: true,
+        profile_file: "surfaceflinger/surfaceflinger.profdata",
+    },
     // TODO(b/131771163): Fix broken fuzzer support with LTO.
     sanitize: {
         fuzzer: false,
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index ec81ff7..097f7de 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -366,8 +366,11 @@
         mFrameTracker.setFrameReadyTime(desiredPresentTime);
     }
 
+    const Fps refreshRate = mFlinger->mRefreshRateConfigs->getCurrentRefreshRate().getFps();
+    const std::optional<Fps> renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
     if (presentFence->isValid()) {
-        mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence);
+        mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence,
+                                              refreshRate, renderRate);
         mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber,
                                            presentFence, FrameTracer::FrameEvent::PRESENT_FENCE);
         mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
@@ -378,7 +381,8 @@
         // The HWC doesn't support present fences, so use the refresh
         // timestamp instead.
         const nsecs_t actualPresentTime = display->getRefreshTimestamp();
-        mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime);
+        mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
+                                             refreshRate, renderRate);
         mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
                                                actualPresentTime,
                                                FrameTracer::FrameEvent::PRESENT_FENCE);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index cf87f62..f30e1eb 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -35,6 +35,7 @@
 #include <renderengine/Image.h>
 
 #include "EffectLayer.h"
+#include "FrameTracer/FrameTracer.h"
 #include "TimeStats/TimeStats.h"
 
 namespace android {
@@ -235,10 +236,6 @@
 bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
     mCurrentStateModified = mCurrentState.modified;
     bool stateUpdateAvailable = Layer::applyPendingStates(stateToCommit);
-    if (stateUpdateAvailable && mCallbackHandleAcquireTime != -1) {
-        // Update the acquire fence time if we have a buffer
-        mSurfaceFrame->setAcquireFenceTime(mCallbackHandleAcquireTime);
-    }
     mCurrentStateModified = stateUpdateAvailable && mCurrentStateModified;
     mCurrentState.modified = false;
     return stateUpdateAvailable;
@@ -337,7 +334,7 @@
 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();
 
@@ -377,6 +374,14 @@
         setFrameTimelineVsyncForBufferTransaction(info, postTime);
     }
 
+    if (dequeueTime && *dequeueTime != 0) {
+        const uint64_t bufferId = buffer->getId();
+        mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
+        mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime,
+                                               FrameTracer::FrameEvent::DEQUEUE);
+        mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, postTime,
+                                               FrameTracer::FrameEvent::QUEUE);
+    }
     return true;
 }
 
@@ -452,6 +457,7 @@
         if (willPresent) {
             // If this transaction set an acquire fence on this layer, set its acquire time
             handle->acquireTime = mCallbackHandleAcquireTime;
+            handle->frameNumber = mCurrentState.frameNumber;
 
             // Notify the transaction completed thread that there is a pending latched callback
             // handle
@@ -602,11 +608,12 @@
 }
 
 std::optional<nsecs_t> BufferStateLayer::nextPredictedPresentTime() const {
-    if (!getDrawingState().isAutoTimestamp || !mSurfaceFrame) {
+    const State& drawingState(getDrawingState());
+    if (!drawingState.isAutoTimestamp || !drawingState.bufferSurfaceFrameTX) {
         return std::nullopt;
     }
 
-    return mSurfaceFrame->getPredictions().presentTime;
+    return drawingState.bufferSurfaceFrameTX->getPredictions().presentTime;
 }
 
 status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
@@ -623,14 +630,22 @@
     }
 
     for (auto& handle : mDrawingState.callbackHandles) {
-        handle->latchTime = latchTime;
-        handle->frameNumber = mDrawingState.frameNumber;
+        if (handle->frameNumber == mDrawingState.frameNumber) {
+            handle->latchTime = latchTime;
+        }
     }
 
     const int32_t layerId = getSequence();
-    mFlinger->mTimeStats->setAcquireFence(layerId, mDrawingState.frameNumber,
-                                          std::make_shared<FenceTime>(mDrawingState.acquireFence));
-    mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime);
+    const uint64_t bufferId = mDrawingState.buffer->getId();
+    const uint64_t frameNumber = mDrawingState.frameNumber;
+    const auto acquireFence = std::make_shared<FenceTime>(mDrawingState.acquireFence);
+    mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence);
+    mFlinger->mTimeStats->setLatchTime(layerId, frameNumber, latchTime);
+
+    mFlinger->mFrameTracer->traceFence(layerId, bufferId, frameNumber, acquireFence,
+                                       FrameTracer::FrameEvent::ACQUIRE_FENCE);
+    mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, latchTime,
+                                           FrameTracer::FrameEvent::LATCH);
 
     auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX;
     if (bufferSurfaceFrame != nullptr &&
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index ea832a2..175a40b 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -124,6 +124,7 @@
 
 private:
     friend class SlotGenerationTest;
+    friend class TransactionFrameTracerTest;
     friend class TransactionSurfaceFrameTest;
 
     inline void tracePendingBufferCount();
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 57dc60b..50bc5ed 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "libcompositionengine_defaults",
     defaults: ["surfaceflinger_defaults"],
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
index 95ba9f0..633668e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -21,9 +21,9 @@
 #include <string>
 
 #include <ui/DisplayId.h>
-#include <ui/DisplayInfo.h>
 #include <ui/PixelFormat.h>
 #include <ui/Size.h>
+#include <ui/StaticDisplayInfo.h>
 
 #include "DisplayHardware/DisplayIdentification.h"
 #include "DisplayHardware/PowerAdvisor.h"
@@ -39,7 +39,7 @@
 struct DisplayCreationArgs {
     struct Physical {
         DisplayId id;
-        DisplayConnectionType type;
+        ui::DisplayConnectionType type;
     };
 
     // Required for physical displays. Gives the HWC display id for the existing
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index c445d5b..8402149 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -34,6 +34,7 @@
 #include <gui/BufferQueue.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/GraphicTypes.h>
+#include <ui/StretchEffect.h>
 
 #include "DisplayHardware/Hal.h"
 
@@ -123,6 +124,8 @@
     // List of regions that require blur
     std::vector<BlurRegion> blurRegions;
 
+    StretchEffect stretchEffect;
+
     /*
      * Geometry state
      */
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
index 782c8d7..6b9597b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
@@ -24,6 +24,7 @@
 #include <ui/FloatRect.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
+#include <ui/StretchEffect.h>
 #include <ui/Transform.h>
 
 namespace android::compositionengine::impl {
@@ -58,5 +59,6 @@
 void dumpVal(std::string& out, const char* name, const ui::Size&);
 
 void dumpVal(std::string& out, const char* name, const mat4& tr);
+void dumpVal(std::string& out, const char* name, const StretchEffect&);
 
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 0b0b8d5..a605fe1 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -55,7 +55,8 @@
     editState().isSecure = args.isSecure;
     editState().displaySpace.bounds = Rect(args.pixels);
     setLayerStackFilter(args.layerStackId,
-                        args.physical && args.physical->type == DisplayConnectionType::Internal);
+                        args.physical &&
+                                args.physical->type == ui::DisplayConnectionType::Internal);
     setName(args.name);
     mGpuVirtualDisplayIdGenerator = args.gpuVirtualDisplayIdGenerator;
 
diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
index 9d1bb02..0cc2c6e 100644
--- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -100,4 +100,10 @@
                   ); /* clang-format on */
 }
 
+void dumpVal(std::string& out, const char* name, const StretchEffect& effect) {
+    StringAppendF(&out, "%s={ area=[%f, %f, %f, %f], vec=(%f, %f), max=%f } ", name,
+                  effect.area.left, effect.area.top, effect.area.right, effect.area.bottom,
+                  effect.vectorX, effect.vectorY, effect.maxAmount);
+}
+
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index 1338538..430945a 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -74,6 +74,9 @@
     dumpVal(out, "blend", toString(blendMode), blendMode);
     dumpVal(out, "alpha", alpha);
     dumpVal(out, "backgroundBlurRadius", backgroundBlurRadius);
+    if (stretchEffect.hasEffect()) {
+        dumpVal(out, "stretchEffect", stretchEffect);
+    }
 
     if (!metadata.empty()) {
         out.append("\n      metadata {");
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/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 348ec39..8a83639 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -35,8 +35,8 @@
 #include <compositionengine/mock/RenderSurface.h>
 #include <gtest/gtest.h>
 #include <renderengine/mock/RenderEngine.h>
-#include <ui/DisplayInfo.h>
 #include <ui/Rect.h>
+#include <ui/StaticDisplayInfo.h>
 
 #include "MockHWC2.h"
 #include "MockHWComposer.h"
@@ -169,7 +169,7 @@
 
     DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() {
         return DisplayCreationArgsBuilder()
-                .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+                .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
                 .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
                 .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
                 .setIsSecure(true)
@@ -265,7 +265,7 @@
     mDisplay->setConfiguration(
             DisplayCreationArgsBuilder()
                     .setUseHwcVirtualDisplays(true)
-                    .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+                    .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
                     .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH))
                     .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
                     .setIsSecure(true)
@@ -286,7 +286,7 @@
     mDisplay->setConfiguration(
             DisplayCreationArgsBuilder()
                     .setUseHwcVirtualDisplays(true)
-                    .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::External})
+                    .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::External})
                     .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH))
                     .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
                     .setIsSecure(false)
@@ -1018,7 +1018,7 @@
     std::shared_ptr<Display> mDisplay = impl::createDisplayTemplated<
             Display>(mCompositionEngine,
                      DisplayCreationArgsBuilder()
-                             .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+                             .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
                              .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
                              .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
                              .setIsSecure(true)
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index ab00385..bac894a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -91,7 +91,7 @@
     MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(PhysicalDisplayId));
     MOCK_METHOD3(setActiveColorMode, status_t(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent));
     MOCK_CONST_METHOD0(isUsingVrComposer, bool());
-    MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(PhysicalDisplayId));
+    MOCK_CONST_METHOD1(getDisplayConnectionType, ui::DisplayConnectionType(PhysicalDisplayId));
     MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(PhysicalDisplayId));
     MOCK_CONST_METHOD2(getDisplayVsyncPeriod, status_t(PhysicalDisplayId, nsecs_t*));
     MOCK_METHOD4(setActiveModeWithConstraints,
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/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a785968..36c4c4d 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -173,7 +173,7 @@
 
 DisplayModePtr DisplayDevice::getMode(DisplayModeId modeId) const {
     const auto id = modeId.value();
-    if (id < mSupportedModes.size()) {
+    if (static_cast<size_t>(id) < mSupportedModes.size()) {
         return mSupportedModes[id];
     }
     return nullptr;
@@ -254,7 +254,7 @@
 std::string DisplayDevice::getDebugName() const {
     const char* type = "virtual";
     if (mConnectionType) {
-        type = *mConnectionType == DisplayConnectionType::Internal ? "internal" : "external";
+        type = *mConnectionType == ui::DisplayConnectionType::Internal ? "internal" : "external";
     }
 
     return base::StringPrintf("DisplayDevice{%s, %s%s, \"%s\"}", to_string(getId()).c_str(), type,
@@ -265,7 +265,8 @@
     StringAppendF(&result, "+ %s\n", getDebugName().c_str());
     StringAppendF(&result, "   powerMode=%s (%d)\n", to_string(mPowerMode).c_str(),
                   static_cast<int32_t>(mPowerMode));
-    StringAppendF(&result, "   activeMode=%s\n", to_string(*getActiveMode()).c_str());
+    StringAppendF(&result, "   activeMode=%s\n",
+                  mSupportedModes.size() ? to_string(*getActiveMode()).c_str() : "none");
 
     result.append("   supportedModes=\n");
 
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index b4db933..a94bfa2 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -28,11 +28,11 @@
 #include <renderengine/RenderEngine.h>
 #include <system/window.h>
 #include <ui/DisplayId.h>
-#include <ui/DisplayInfo.h>
 #include <ui/DisplayState.h>
 #include <ui/GraphicTypes.h>
 #include <ui/HdrCapabilities.h>
 #include <ui/Region.h>
+#include <ui/StaticDisplayInfo.h>
 #include <ui/Transform.h>
 #include <utils/Errors.h>
 #include <utils/Mutex.h>
@@ -74,7 +74,7 @@
         return mCompositionDisplay;
     }
 
-    std::optional<DisplayConnectionType> getConnectionType() const { return mConnectionType; }
+    std::optional<ui::DisplayConnectionType> getConnectionType() const { return mConnectionType; }
 
     bool isVirtual() const { return !mConnectionType; }
     bool isPrimary() const { return mIsPrimary; }
@@ -195,7 +195,7 @@
     HWComposer& mHwComposer;
     const wp<IBinder> mDisplayToken;
     const int32_t mSequenceId;
-    const std::optional<DisplayConnectionType> mConnectionType;
+    const std::optional<ui::DisplayConnectionType> mConnectionType;
 
     const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
 
@@ -222,7 +222,7 @@
 struct DisplayDeviceState {
     struct Physical {
         PhysicalDisplayId id;
-        DisplayConnectionType type;
+        ui::DisplayConnectionType type;
         hardware::graphics::composer::hal::HWDisplayId hwcDisplayId;
         std::optional<DeviceProductInfo> deviceProductInfo;
         DisplayModes supportedModes;
@@ -263,7 +263,7 @@
     const std::shared_ptr<compositionengine::Display> compositionDisplay;
 
     int32_t sequenceId{0};
-    std::optional<DisplayConnectionType> connectionType;
+    std::optional<ui::DisplayConnectionType> connectionType;
     bool isSecure{false};
     sp<ANativeWindow> nativeWindow;
     sp<compositionengine::DisplaySurface> displaySurface;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 31d1245..853c05b 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayMode.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -22,6 +22,7 @@
 
 #include <android-base/stringprintf.h>
 #include <android/configuration.h>
+#include <ui/DisplayMode.h>
 #include <ui/Size.h>
 #include <utils/Timers.h>
 
@@ -36,7 +37,7 @@
 class DisplayMode;
 using DisplayModePtr = std::shared_ptr<const DisplayMode>;
 using DisplayModes = std::vector<DisplayModePtr>;
-using DisplayModeId = StrongTyping<size_t, struct DisplayModeIdTag, Compare, Hash>;
+using DisplayModeId = StrongTyping<ui::DisplayModeId, struct DisplayModeIdTag, Compare, Hash>;
 
 class DisplayMode {
 public:
@@ -86,8 +87,8 @@
             return *this;
         }
 
-        Builder& setConfigGroup(int32_t configGroup) {
-            mDisplayMode->mConfigGroup = configGroup;
+        Builder& setGroup(int32_t group) {
+            mDisplayMode->mGroup = group;
             return *this;
         }
 
@@ -119,7 +120,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 +136,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}",
+    return base::StringPrintf("{id=%d, hwcId=%d, width=%d, height=%d, refreshRate=%s, "
+                              "dpiX=%.2f, dpiY=%.2f, group=%d}",
                               mode.getId().value(), mode.getHwcId(), mode.getWidth(),
                               mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpiX(),
-                              mode.getDpiY(), mode.getConfigGroup());
+                              mode.getDpiY(), mode.getGroup());
 }
 
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 71a3276..d04b5f7 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -264,7 +264,7 @@
     return Error::NONE;
 }
 
-Error Display::getConnectionType(android::DisplayConnectionType* outType) const {
+Error Display::getConnectionType(ui::DisplayConnectionType* outType) const {
     if (mType != DisplayType::PHYSICAL) return Error::BAD_DISPLAY;
 
     using ConnectionType = Hwc2::IComposerClient::DisplayConnectionType;
@@ -274,9 +274,8 @@
         return error;
     }
 
-    *outType = connectionType == ConnectionType::INTERNAL
-            ? android::DisplayConnectionType::Internal
-            : android::DisplayConnectionType::External;
+    *outType = connectionType == ConnectionType::INTERNAL ? ui::DisplayConnectionType::Internal
+                                                          : ui::DisplayConnectionType::External;
     return Error::NONE;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 4c7f284..e7bf286 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -18,9 +18,9 @@
 
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
-#include <ui/DisplayInfo.h>
 #include <ui/HdrCapabilities.h>
 #include <ui/Region.h>
+#include <ui/StaticDisplayInfo.h>
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
 #include <utils/Timers.h>
@@ -104,7 +104,7 @@
             hal::DisplayRequest* outDisplayRequests,
             std::unordered_map<Layer*, hal::LayerRequest>* outLayerRequests) = 0;
     [[clang::warn_unused_result]] virtual hal::Error getConnectionType(
-            android::DisplayConnectionType*) const = 0;
+            ui::DisplayConnectionType*) const = 0;
     [[clang::warn_unused_result]] virtual hal::Error supportsDoze(bool* outSupport) const = 0;
     [[clang::warn_unused_result]] virtual hal::Error getHdrCapabilities(
             android::HdrCapabilities* outCapabilities) const = 0;
@@ -175,7 +175,7 @@
     hal::Error getRequests(
             hal::DisplayRequest* outDisplayRequests,
             std::unordered_map<Layer*, hal::LayerRequest>* outLayerRequests) override;
-    hal::Error getConnectionType(android::DisplayConnectionType*) const override;
+    hal::Error getConnectionType(ui::DisplayConnectionType*) const override;
     hal::Error supportsDoze(bool* outSupport) const override;
     hal::Error getHdrCapabilities(android::HdrCapabilities* outCapabilities) const override;
     hal::Error getDisplayedContentSamplingAttributes(hal::PixelFormat* outFormat,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index b9a8e4b..ccfaa76 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -369,16 +369,16 @@
 
 // Composer 2.4
 
-DisplayConnectionType HWComposer::getDisplayConnectionType(PhysicalDisplayId displayId) const {
-    RETURN_IF_INVALID_DISPLAY(displayId, DisplayConnectionType::Internal);
+ui::DisplayConnectionType HWComposer::getDisplayConnectionType(PhysicalDisplayId displayId) const {
+    RETURN_IF_INVALID_DISPLAY(displayId, ui::DisplayConnectionType::Internal);
     const auto& hwcDisplay = mDisplayData.at(displayId).hwcDisplay;
 
-    DisplayConnectionType type;
+    ui::DisplayConnectionType type;
     const auto error = hwcDisplay->getConnectionType(&type);
 
     const auto FALLBACK_TYPE = hwcDisplay->getId() == mInternalHwcDisplayId
-            ? DisplayConnectionType::Internal
-            : DisplayConnectionType::External;
+            ? ui::DisplayConnectionType::Internal
+            : ui::DisplayConnectionType::External;
 
     RETURN_IF_HWC_ERROR(error, displayId, FALLBACK_TYPE);
     return type;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index f9c8e2e..cf6bc68 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -204,7 +204,7 @@
                                         ui::RenderIntent) = 0;
 
     // Composer 2.4
-    virtual DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const = 0;
+    virtual ui::DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const = 0;
     virtual bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const = 0;
     virtual status_t getDisplayVsyncPeriod(PhysicalDisplayId displayId,
                                            nsecs_t* outVsyncPeriod) const = 0;
@@ -335,7 +335,7 @@
     status_t setActiveColorMode(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent) override;
 
     // Composer 2.4
-    DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override;
+    ui::DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override;
     bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const override;
     status_t getDisplayVsyncPeriod(PhysicalDisplayId displayId,
                                    nsecs_t* outVsyncPeriod) const override;
diff --git a/services/surfaceflinger/Fps.h b/services/surfaceflinger/Fps.h
index 38a9af0..e9f06e5 100644
--- a/services/surfaceflinger/Fps.h
+++ b/services/surfaceflinger/Fps.h
@@ -27,7 +27,7 @@
 
 // Value which represents "frames per second". This class is a wrapper around
 // float, providing some useful utilities, such as comparisons with tolerance
-// and converting between period duruation and frequency.
+// and converting between period duration and frequency.
 class Fps {
 public:
     static constexpr Fps fromPeriodNsecs(nsecs_t period) { return Fps(1e9f / period, period); }
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 3f833f4..da04202 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -30,6 +30,7 @@
 
 using base::StringAppendF;
 using FrameTimelineEvent = perfetto::protos::pbzero::FrameTimelineEvent;
+using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource;
 
 void dumpTable(std::string& result, TimelineItem predictions, TimelineItem actuals,
                const std::string& indent, PredictionState predictionState, nsecs_t baseTime) {
@@ -305,11 +306,17 @@
     std::scoped_lock lock(mMutex);
     mActualQueueTime = actualQueueTime;
 }
+
 void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) {
     std::scoped_lock lock(mMutex);
     mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime);
 }
 
+void SurfaceFrame::setDropTime(nsecs_t dropTime) {
+    std::scoped_lock lock(mMutex);
+    mDropTime = dropTime;
+}
+
 void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchTime) {
     std::scoped_lock lock(mMutex);
     LOG_ALWAYS_FATAL_IF(mPresentState != PresentState::Unknown,
@@ -320,9 +327,19 @@
     mLastLatchTime = lastLatchTime;
 }
 
+void SurfaceFrame::setRenderRate(Fps renderRate) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mRenderRate = renderRate;
+}
+
 std::optional<int32_t> SurfaceFrame::getJankType() const {
     std::scoped_lock lock(mMutex);
+    if (mPresentState == PresentState::Dropped) {
+        // Return no jank if it's a dropped frame since we cannot attribute a jank to a it.
+        return JankType::None;
+    }
     if (mActuals.presentTime == 0) {
+        // Frame hasn't been presented yet.
         return std::nullopt;
     }
     return mJankType;
@@ -338,6 +355,11 @@
     return mActuals;
 }
 
+PredictionState SurfaceFrame::getPredictionState() const {
+    std::scoped_lock lock(mMutex);
+    return mPredictionState;
+}
+
 SurfaceFrame::PresentState SurfaceFrame::getPresentState() const {
     std::scoped_lock lock(mMutex);
     return mPresentState;
@@ -353,6 +375,11 @@
     return mFrameReadyMetadata;
 }
 
+nsecs_t SurfaceFrame::getDropTime() const {
+    std::scoped_lock lock(mMutex);
+    return mDropTime;
+}
+
 void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) const {
     std::scoped_lock lock(mMutex);
     StringAppendF(&result, "%s", indent.c_str());
@@ -367,8 +394,17 @@
     StringAppendF(&result, "%s", indent.c_str());
     StringAppendF(&result, "Owner Pid : %d\n", mOwnerPid);
     StringAppendF(&result, "%s", indent.c_str());
+    StringAppendF(&result, "Scheduled rendering rate: %d fps\n",
+                  mRenderRate ? mRenderRate->getIntValue() : 0);
+    StringAppendF(&result, "%s", indent.c_str());
     StringAppendF(&result, "Present State : %s\n", toString(mPresentState).c_str());
     StringAppendF(&result, "%s", indent.c_str());
+    if (mPresentState == PresentState::Dropped) {
+        std::chrono::nanoseconds dropTime(mDropTime - baseTime);
+        StringAppendF(&result, "Drop time : %10f\n",
+                      std::chrono::duration<double, std::milli>(dropTime).count());
+        StringAppendF(&result, "%s", indent.c_str());
+    }
     StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
     StringAppendF(&result, "%s", indent.c_str());
     StringAppendF(&result, "Jank Type : %s\n", jankTypeBitmaskToString(mJankType).c_str());
@@ -391,9 +427,10 @@
     dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
 }
 
-void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
-                             nsecs_t vsyncPeriod) {
+void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate,
+                             nsecs_t displayDeadlineDelta, nsecs_t displayPresentDelta) {
     std::scoped_lock lock(mMutex);
+
     if (mPresentState != PresentState::Presented) {
         // No need to update dropped buffers
         return;
@@ -412,13 +449,16 @@
         mJankType = JankType::Unknown;
         mFramePresentMetadata = FramePresentMetadata::UnknownPresent;
         mFrameReadyMetadata = FrameReadyMetadata::UnknownFinish;
-        mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
+        const constexpr nsecs_t kAppDeadlineDelta = -1;
+        mTimeStats->incrementJankyFrames({refreshRate, mRenderRate, mOwnerUid, mLayerName,
+                                          mJankType, displayDeadlineDelta, displayPresentDelta,
+                                          kAppDeadlineDelta});
         return;
     }
 
     const nsecs_t presentDelta = mActuals.presentTime - mPredictions.presentTime;
     const nsecs_t deadlineDelta = mActuals.endTime - mPredictions.endTime;
-    const nsecs_t deltaToVsync = std::abs(presentDelta) % vsyncPeriod;
+    const nsecs_t deltaToVsync = std::abs(presentDelta) % refreshRate.getPeriodNsecs();
 
     if (deadlineDelta > mJankClassificationThresholds.deadlineThreshold) {
         mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
@@ -440,7 +480,8 @@
         if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
             // Finish on time, Present early
             if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
-                deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
+                deltaToVsync >= refreshRate.getPeriodNsecs() -
+                                mJankClassificationThresholds.presentThreshold) {
                 // Delta factor of vsync
                 mJankType = JankType::SurfaceFlingerScheduling;
             } else {
@@ -463,7 +504,8 @@
                 mJankType |= displayFrameJankType;
             } else {
                 if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
-                    deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
+                    deltaToVsync >= refreshRate.getPeriodNsecs() -
+                                    mJankClassificationThresholds.presentThreshold) {
                     // Delta factor of vsync
                     mJankType |= JankType::SurfaceFlingerScheduling;
                 } else {
@@ -482,30 +524,16 @@
             }
         }
     }
-    mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
+    mTimeStats->incrementJankyFrames({refreshRate, mRenderRate, mOwnerUid, mLayerName, mJankType,
+                                      displayDeadlineDelta, displayPresentDelta, deadlineDelta});
 }
 
-/**
- * TODO(b/178637512): add inputEventId to the perfetto trace.
- */
-void SurfaceFrame::trace(int64_t displayFrameToken) {
-    using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource;
-
+void SurfaceFrame::tracePredictions(int64_t displayFrameToken) const {
     int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
-    bool missingToken = false;
+
     // Expected timeline start
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
         std::scoped_lock lock(mMutex);
-        if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
-            ALOGD("Cannot trace SurfaceFrame - %s with invalid token", mLayerName.c_str());
-            missingToken = true;
-            return;
-        } else if (displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
-            ALOGD("Cannot trace SurfaceFrame  - %s with invalid displayFrameToken",
-                  mLayerName.c_str());
-            missingToken = true;
-            return;
-        }
         auto packet = ctx.NewTracePacket();
         packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
         packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
@@ -522,12 +550,6 @@
         expectedSurfaceFrameStartEvent->set_layer_name(mDebugName);
     });
 
-    if (missingToken) {
-        // If one packet can't be traced because of missing token, then no packets can be traced.
-        // Exit early in this case.
-        return;
-    }
-
     // Expected timeline end
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
         std::scoped_lock lock(mMutex);
@@ -540,15 +562,26 @@
 
         expectedSurfaceFrameEndEvent->set_cookie(expectedTimelineCookie);
     });
+}
 
+void SurfaceFrame::traceActuals(int64_t displayFrameToken) const {
     int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
+
     // Actual timeline start
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
         std::scoped_lock lock(mMutex);
         auto packet = ctx.NewTracePacket();
         packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
         // Actual start time is not yet available, so use expected start instead
-        packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
+        if (mPredictionState == PredictionState::Expired) {
+            // If prediction is expired, we can't use the predicted start time. Instead, just use a
+            // start time a little earlier than the end time so that we have some info about this
+            // frame in the trace.
+            packet->set_timestamp(
+                    static_cast<uint64_t>(mActuals.endTime - kPredictionExpiredStartTimeDelta));
+        } else {
+            packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
+        }
 
         auto* event = packet->set_frame_timeline_event();
         auto* actualSurfaceFrameStartEvent = event->set_actual_surface_frame_start();
@@ -573,12 +606,17 @@
         actualSurfaceFrameStartEvent->set_gpu_composition(mGpuComposition);
         actualSurfaceFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
     });
+
     // Actual timeline end
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
         std::scoped_lock lock(mMutex);
         auto packet = ctx.NewTracePacket();
         packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
-        packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime));
+        if (mPresentState == PresentState::Dropped) {
+            packet->set_timestamp(static_cast<uint64_t>(mDropTime));
+        } else {
+            packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime));
+        }
 
         auto* event = packet->set_frame_timeline_event();
         auto* actualSurfaceFrameEndEvent = event->set_frame_end();
@@ -587,6 +625,23 @@
     });
 }
 
+/**
+ * TODO(b/178637512): add inputEventId to the perfetto trace.
+ */
+void SurfaceFrame::trace(int64_t displayFrameToken) const {
+    if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID ||
+        displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
+        // No packets can be traced with a missing token.
+        return;
+    }
+    if (getPredictionState() != PredictionState::Expired) {
+        // Expired predictions have zeroed timestamps. This cannot be used in any meaningful way in
+        // a trace.
+        tracePredictions(displayFrameToken);
+    }
+    traceActuals(displayFrameToken);
+}
+
 namespace impl {
 
 int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
@@ -684,10 +739,10 @@
     mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame);
 }
 
-void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) {
+void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRate) {
     ATRACE_CALL();
     std::scoped_lock lock(mMutex);
-    mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod,
+    mCurrentDisplayFrame->onSfWakeUp(token, refreshRate,
                                      mTokenManager.getPredictionsForToken(token), wakeUpTime);
 }
 
@@ -705,11 +760,11 @@
     mSurfaceFrames.push_back(surfaceFrame);
 }
 
-void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, nsecs_t vsyncPeriod,
+void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, Fps refreshRate,
                                              std::optional<TimelineItem> predictions,
                                              nsecs_t wakeUpTime) {
     mToken = token;
-    mVsyncPeriod = vsyncPeriod;
+    mRefreshRate = refreshRate;
     if (!predictions) {
         mPredictionState = PredictionState::Expired;
     } else {
@@ -719,11 +774,6 @@
     mSurfaceFlingerActuals.startTime = wakeUpTime;
 }
 
-void FrameTimeline::DisplayFrame::setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod) {
-    mToken = token;
-    mVsyncPeriod = vsyncPeriod;
-}
-
 void FrameTimeline::DisplayFrame::setPredictions(PredictionState predictionState,
                                                  TimelineItem predictions) {
     mPredictionState = predictionState;
@@ -740,14 +790,21 @@
 
 void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
     mSurfaceFlingerActuals.presentTime = signalTime;
-    int32_t totalJankReasons = JankType::None;
+    if (mPredictionState == PredictionState::Expired) {
+        // Cannot do jank classification with expired predictions
+        mJankType = JankType::Unknown;
+        return;
+    }
 
     // Delta between the expected present and the actual present
     const nsecs_t presentDelta =
             mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
+    const nsecs_t deadlineDelta =
+            mSurfaceFlingerActuals.endTime - mSurfaceFlingerPredictions.endTime;
+
     // How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there
     // was a prediction error or not.
-    nsecs_t deltaToVsync = std::abs(presentDelta) % mVsyncPeriod;
+    nsecs_t deltaToVsync = std::abs(presentDelta) % mRefreshRate.getPeriodNsecs();
     if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
         mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
                                                  : FramePresentMetadata::EarlyPresent;
@@ -776,8 +833,8 @@
             if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
                 // Finish on time, Present early
                 if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
-                    deltaToVsync >=
-                            (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
+                    deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
+                                     mJankClassificationThresholds.presentThreshold)) {
                     // Delta is a factor of vsync if its within the presentTheshold on either side
                     // of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
                     // of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
@@ -797,8 +854,8 @@
             if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
                 // Finish on time, Present late
                 if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
-                    deltaToVsync >=
-                            (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
+                    deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
+                                     mJankClassificationThresholds.presentThreshold)) {
                     // Delta is a factor of vsync if its within the presentTheshold on either side
                     // of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
                     // of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
@@ -819,29 +876,17 @@
             mJankType = JankType::Unknown;
         }
     }
-    totalJankReasons |= mJankType;
-
     for (auto& surfaceFrame : mSurfaceFrames) {
-        surfaceFrame->onPresent(signalTime, mJankType, mVsyncPeriod);
-        auto surfaceFrameJankType = surfaceFrame->getJankType();
-        if (surfaceFrameJankType != std::nullopt) {
-            totalJankReasons |= *surfaceFrameJankType;
-        }
+        surfaceFrame->onPresent(signalTime, mJankType, mRefreshRate, deadlineDelta, deltaToVsync);
     }
-    mTimeStats->incrementJankyFrames(totalJankReasons);
 }
 
-void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
+void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid) const {
     int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
-    bool missingToken = false;
+
     // Expected timeline start
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
         auto packet = ctx.NewTracePacket();
-        if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
-            ALOGD("Cannot trace DisplayFrame with invalid token");
-            missingToken = true;
-            return;
-        }
         packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
         packet->set_timestamp(static_cast<uint64_t>(mSurfaceFlingerPredictions.startTime));
 
@@ -854,12 +899,6 @@
         expectedDisplayFrameStartEvent->set_pid(surfaceFlingerPid);
     });
 
-    if (missingToken) {
-        // If one packet can't be traced because of missing token, then no packets can be traced.
-        // Exit early in this case.
-        return;
-    }
-
     // Expected timeline end
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
         auto packet = ctx.NewTracePacket();
@@ -871,9 +910,12 @@
 
         expectedDisplayFrameEndEvent->set_cookie(expectedTimelineCookie);
     });
+}
 
+void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid) const {
     int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing();
-    // Expected timeline start
+
+    // Actual timeline start
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
         auto packet = ctx.NewTracePacket();
         packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
@@ -893,7 +935,8 @@
         actualDisplayFrameStartEvent->set_gpu_composition(mGpuComposition);
         actualDisplayFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
     });
-    // Expected timeline end
+
+    // Actual timeline end
     FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
         auto packet = ctx.NewTracePacket();
         packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
@@ -904,6 +947,21 @@
 
         actualDisplayFrameEndEvent->set_cookie(actualTimelineCookie);
     });
+}
+
+void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
+    if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) {
+        // DisplayFrame should not have an invalid token.
+        ALOGE("Cannot trace DisplayFrame with invalid token");
+        return;
+    }
+
+    if (mPredictionState == PredictionState::Valid) {
+        // Expired and unknown predictions have zeroed timestamps. This cannot be used in any
+        // meaningful way in a trace.
+        tracePredictions(surfaceFlingerPid);
+    }
+    traceActuals(surfaceFlingerPid);
 
     for (auto& surfaceFrame : mSurfaceFrames) {
         surfaceFrame->trace(mToken);
@@ -988,7 +1046,7 @@
     StringAppendF(&result, "Present Metadata : %s\n", toString(mFramePresentMetadata).c_str());
     StringAppendF(&result, "Finish Metadata: %s\n", toString(mFrameReadyMetadata).c_str());
     StringAppendF(&result, "Start Metadata: %s\n", toString(mFrameStartMetadata).c_str());
-    std::chrono::nanoseconds vsyncPeriod(mVsyncPeriod);
+    std::chrono::nanoseconds vsyncPeriod(mRefreshRate.getPeriodNsecs());
     StringAppendF(&result, "Vsync Period: %10f\n",
                   std::chrono::duration<double, std::milli>(vsyncPeriod).count());
     nsecs_t presentDelta =
@@ -996,7 +1054,7 @@
     std::chrono::nanoseconds presentDeltaNs(std::abs(presentDelta));
     StringAppendF(&result, "Present delta: %10f\n",
                   std::chrono::duration<double, std::milli>(presentDeltaNs).count());
-    std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mVsyncPeriod);
+    std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mRefreshRate.getPeriodNsecs());
     StringAppendF(&result, "Present delta %% refreshrate: %10f\n",
                   std::chrono::duration<double, std::milli>(deltaToVsync).count());
     dumpTable(result, mSurfaceFlingerPredictions, mSurfaceFlingerActuals, "", mPredictionState,
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 54e8efb..8f3157d 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <../Fps.h>
 #include <../TimeStats/TimeStats.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/JankInfo.h>
@@ -170,34 +171,50 @@
     TimelineItem getPredictions() const { return mPredictions; };
     // Actual timestamps of the app are set individually at different functions.
     // Start time (if the app provides) and Queue time are accessible after queueing the frame,
-    // whereas Acquire Fence time is available only during latch.
+    // whereas Acquire Fence time is available only during latch. Drop time is available at the time
+    // the buffer was dropped.
     void setActualStartTime(nsecs_t actualStartTime);
     void setActualQueueTime(nsecs_t actualQueueTime);
     void setAcquireFenceTime(nsecs_t acquireFenceTime);
+    void setDropTime(nsecs_t dropTime);
     void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0);
+    void setRenderRate(Fps renderRate);
 
     // Functions called by FrameTimeline
     // BaseTime is the smallest timestamp in this SurfaceFrame.
     // Used for dumping all timestamps relative to the oldest, making it easy to read.
     nsecs_t getBaseTime() const;
     // Sets the actual present time, appropriate metadata and classifies the jank.
-    void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, nsecs_t vsyncPeriod);
+    // displayRefreshRate, displayDeadlineDelta, and displayPresentDelta are propagated from the
+    // display frame.
+    void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate,
+                   nsecs_t displayDeadlineDelta, nsecs_t displayPresentDelta);
     // All the timestamps are dumped relative to the baseTime
     void dump(std::string& result, const std::string& indent, nsecs_t baseTime) const;
     // Emits a packet for perfetto tracing. The function body will be executed only if tracing is
     // enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding
     // DisplayFrame at the trace processor side.
-    void trace(int64_t displayFrameToken);
+    void trace(int64_t displayFrameToken) const;
 
-    // Getter functions used only by FrameTimelineTests
+    // Getter functions used only by FrameTimelineTests and SurfaceFrame internally
     TimelineItem getActuals() const;
     pid_t getOwnerPid() const { return mOwnerPid; };
-    PredictionState getPredictionState() const { return mPredictionState; };
+    PredictionState getPredictionState() const;
     PresentState getPresentState() const;
     FrameReadyMetadata getFrameReadyMetadata() const;
     FramePresentMetadata getFramePresentMetadata() const;
+    nsecs_t getDropTime() const;
+
+    // For prediction expired frames, this delta is subtracted from the actual end time to get a
+    // start time decent enough to see in traces.
+    // TODO(b/172587309): Remove this when we have actual start times.
+    static constexpr nsecs_t kPredictionExpiredStartTimeDelta =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
 
 private:
+    void tracePredictions(int64_t displayFrameToken) const;
+    void traceActuals(int64_t displayFrameToken) const;
+
     const int64_t mToken;
     const int32_t mInputEventId;
     const pid_t mOwnerPid;
@@ -211,11 +228,14 @@
     std::shared_ptr<TimeStats> mTimeStats;
     const JankClassificationThresholds mJankClassificationThresholds;
     nsecs_t mActualQueueTime GUARDED_BY(mMutex) = 0;
+    nsecs_t mDropTime GUARDED_BY(mMutex) = 0;
     mutable std::mutex mMutex;
     // Bitmask for the type of jank
     int32_t mJankType GUARDED_BY(mMutex) = JankType::None;
     // Indicates if this frame was composited by the GPU or not
     bool mGpuComposition GUARDED_BY(mMutex) = false;
+    // Rendering rate for this frame.
+    std::optional<Fps> mRenderRate GUARDED_BY(mMutex);
     // Enum for the type of present
     FramePresentMetadata mFramePresentMetadata GUARDED_BY(mMutex) =
             FramePresentMetadata::UnknownPresent;
@@ -255,7 +275,7 @@
 
     // The first function called by SF for the current DisplayFrame. Fetches SF predictions based on
     // the token and sets the actualSfWakeTime for the current DisplayFrame.
-    virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) = 0;
+    virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0;
 
     // Sets the sfPresentTime and finalizes the current DisplayFrame. Tracks the given present fence
     // until it's signaled, and updates the present timestamps of all presented SurfaceFrames in
@@ -325,14 +345,13 @@
         // is enabled.
         void trace(pid_t surfaceFlingerPid) const;
         // Sets the token, vsyncPeriod, predictions and SF start time.
-        void onSfWakeUp(int64_t token, nsecs_t vsyncPeriod, std::optional<TimelineItem> predictions,
+        void onSfWakeUp(int64_t token, Fps refreshRate, std::optional<TimelineItem> predictions,
                         nsecs_t wakeUpTime);
         // Sets the appropriate metadata, classifies the jank and returns the classified jankType.
         void onPresent(nsecs_t signalTime);
         // Adds the provided SurfaceFrame to the current display frame.
         void addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame);
 
-        void setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod);
         void setPredictions(PredictionState predictionState, TimelineItem predictions);
         void setActualStartTime(nsecs_t actualStartTime);
         void setActualEndTime(nsecs_t actualEndTime);
@@ -353,6 +372,8 @@
 
     private:
         void dump(std::string& result, nsecs_t baseTime) const;
+        void tracePredictions(pid_t surfaceFlingerPid) const;
+        void traceActuals(pid_t surfaceFlingerPid) const;
 
         int64_t mToken = FrameTimelineInfo::INVALID_VSYNC_ID;
 
@@ -382,7 +403,7 @@
         FrameStartMetadata mFrameStartMetadata = FrameStartMetadata::UnknownStart;
         // The refresh rate (vsync period) in nanoseconds as seen by SF during this DisplayFrame's
         // timeline
-        nsecs_t mVsyncPeriod = 0;
+        Fps mRefreshRate;
         // TraceCookieCounter is used to obtain the cookie for sendig trace packets to perfetto.
         // Using a reference here because the counter is owned by FrameTimeline, which outlives
         // DisplayFrame.
@@ -398,7 +419,7 @@
             const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
             std::string layerName, std::string debugName) override;
     void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override;
-    void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) override;
+    void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override;
     void setSfPresent(nsecs_t sfPresentTime,
                       const std::shared_ptr<FenceTime>& presentFence) override;
     void parseArgs(const Vector<String16>& args, std::string& result) override;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index df14003..95ab394 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -25,6 +25,7 @@
 
 #include "Layer.h"
 
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android/native_window.h>
 #include <binder/IPCThreadState.h>
@@ -488,6 +489,7 @@
     compositionState->alpha = alpha;
     compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
     compositionState->blurRegions = drawingState.blurRegions;
+    compositionState->stretchEffect = getStretchEffect();
 }
 
 void Layer::prepareGeometryCompositionState() {
@@ -556,8 +558,8 @@
             isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
 
     // Force client composition for special cases known only to the front-end.
-    if (isHdrY410() || usesRoundedCorners || drawShadows() ||
-        getDrawingState().blurRegions.size() > 0) {
+    if (isHdrY410() || usesRoundedCorners || drawShadows() || drawingState.blurRegions.size() > 0 ||
+        compositionState->stretchEffect.hasEffect()) {
         compositionState->forceClientComposition = true;
     }
 }
@@ -656,6 +658,7 @@
         layerSettings.backgroundBlurRadius = getBackgroundBlurRadius();
         layerSettings.blurRegions = getBlurRegions();
     }
+    layerSettings.stretchEffect = getDrawingState().stretchEffect;
     // Record the name of the layer for debugging further down the stack.
     layerSettings.name = getName();
     return layerSettings;
@@ -867,9 +870,7 @@
 void Layer::popPendingState(State* stateToCommit) {
     ATRACE_CALL();
 
-    if (stateToCommit != nullptr) {
-        mergeSurfaceFrames(*stateToCommit, mPendingStates[0]);
-    }
+    mergeSurfaceFrames(*stateToCommit, mPendingStates[0]);
     *stateToCommit = mPendingStates[0];
     mPendingStates.pop_front();
     ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
@@ -1423,6 +1424,35 @@
     return true;
 }
 
+bool Layer::setStretchEffect(const StretchEffect& effect) {
+    StretchEffect temp = effect;
+    temp.sanitize();
+    if (mCurrentState.stretchEffect == temp) {
+        return false;
+    }
+    mCurrentState.sequence++;
+    mCurrentState.stretchEffect = temp;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+StretchEffect Layer::getStretchEffect() const {
+    if (mDrawingState.stretchEffect.hasEffect()) {
+        return mDrawingState.stretchEffect;
+    }
+
+    sp<Layer> parent = getParent();
+    if (parent != nullptr) {
+        auto effect = parent->getStretchEffect();
+        if (effect.hasEffect()) {
+            // TODO(b/179047472): Map it? Or do we make the effect be in global space?
+            return effect;
+        }
+    }
+    return StretchEffect{};
+}
+
 void Layer::updateTreeHasFrameRateVote() {
     const auto traverseTree = [&](const LayerVector::Visitor& visitor) {
         auto parent = getParent();
@@ -1547,6 +1577,7 @@
 
 void Layer::addSurfaceFrameDroppedForBuffer(
         std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) {
+    surfaceFrame->setDropTime(systemTime());
     surfaceFrame->setPresentState(PresentState::Dropped);
     mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
 }
@@ -1568,6 +1599,10 @@
     // For Transactions, the post time is considered to be both queue and acquire fence time.
     surfaceFrame->setActualQueueTime(postTime);
     surfaceFrame->setAcquireFenceTime(postTime);
+    const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
+    if (fps) {
+        surfaceFrame->setRenderRate(*fps);
+    }
     onSurfaceFrameCreated(surfaceFrame);
     return surfaceFrame;
 }
@@ -1579,6 +1614,10 @@
                                                                  debugName);
     // For buffers, acquire fence time will set during latch.
     surfaceFrame->setActualQueueTime(queueTime);
+    const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
+    if (fps) {
+        surfaceFrame->setRenderRate(*fps);
+    }
     // TODO(b/178542907): Implement onSurfaceFrameCreated for BQLayer as well.
     onSurfaceFrameCreated(surfaceFrame);
     return surfaceFrame;
@@ -1719,6 +1758,7 @@
     info.mRefreshPending = isBufferLatched();
     info.mIsOpaque = isOpaque(ds);
     info.mContentDirty = contentDirty;
+    info.mStretchEffect = getStretchEffect();
     return info;
 }
 
@@ -2459,7 +2499,7 @@
     if (traceFlags & SurfaceTracing::TRACE_INPUT) {
         InputWindowInfo info;
         if (useDrawing) {
-            info = fillInputInfo();
+            info = fillInputInfo({nullptr});
         } else {
             info = state.inputInfo;
         }
@@ -2480,7 +2520,7 @@
     return mRemovedFromCurrentState;
 }
 
-void Layer::fillInputFrameInfo(InputWindowInfo& info) {
+void Layer::fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay) {
     // Transform layer size to screen space and inset it by surface insets.
     // If this is a portal window, set the touchableRegion to the layerBounds.
     Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE
@@ -2500,9 +2540,13 @@
         return;
     }
 
-    ui::Transform t = getTransform();
+    ui::Transform layerToDisplay = getTransform();
+    // Transform that takes window coordinates to unrotated display coordinates
+    ui::Transform t = toPhysicalDisplay * layerToDisplay;
     int32_t xSurfaceInset = info.surfaceInset;
     int32_t ySurfaceInset = info.surfaceInset;
+    // Bring screenBounds into unrotated space
+    Rect screenBounds = toPhysicalDisplay.transform(Rect{mScreenBounds});
 
     const float xScale = t.getScaleX();
     const float yScale = t.getScaleY();
@@ -2560,7 +2604,6 @@
     // We need to send the layer bounds cropped to the screenbounds since the layer can be cropped.
     // The frame should be the area the user sees on screen since it's used for occlusion
     // detection.
-    Rect screenBounds = Rect{mScreenBounds};
     transformedLayerBounds.intersect(screenBounds, &transformedLayerBounds);
     info.frameLeft = transformedLayerBounds.left;
     info.frameTop = transformedLayerBounds.top;
@@ -2572,7 +2615,7 @@
     info.touchableRegion = inputTransform.transform(info.touchableRegion);
 }
 
-InputWindowInfo Layer::fillInputInfo() {
+InputWindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) {
     if (!hasInputInfo()) {
         mDrawingState.inputInfo.name = getName();
         mDrawingState.inputInfo.ownerUid = mOwnerUid;
@@ -2589,7 +2632,13 @@
         info.displayId = getLayerStack();
     }
 
-    fillInputFrameInfo(info);
+    // Transform that goes from "logical(rotated)" display to physical/unrotated display.
+    // This is for when inputflinger operates in physical display-space.
+    ui::Transform toPhysicalDisplay;
+    if (display) {
+        toPhysicalDisplay = display->getTransform();
+    }
+    fillInputFrameInfo(info, toPhysicalDisplay);
 
     // For compatibility reasons we let layers which can receive input
     // receive input before they have actually submitted a buffer. Because
@@ -2605,12 +2654,14 @@
     auto cropLayer = mDrawingState.touchableRegionCrop.promote();
     if (info.replaceTouchableRegionWithCrop) {
         if (cropLayer == nullptr) {
-            info.touchableRegion = Region(Rect{mScreenBounds});
+            info.touchableRegion = Region(toPhysicalDisplay.transform(Rect{mScreenBounds}));
         } else {
-            info.touchableRegion = Region(Rect{cropLayer->mScreenBounds});
+            info.touchableRegion =
+                    Region(toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds}));
         }
     } else if (cropLayer != nullptr) {
-        info.touchableRegion = info.touchableRegion.intersect(Rect{cropLayer->mScreenBounds});
+        info.touchableRegion = info.touchableRegion.intersect(
+                toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds}));
     }
 
     // If the layer is a clone, we need to crop the input region to cloned root to prevent
@@ -2618,7 +2669,7 @@
     if (isClone()) {
         sp<Layer> clonedRoot = getClonedRoot();
         if (clonedRoot != nullptr) {
-            Rect rect(clonedRoot->mScreenBounds);
+            Rect rect = toPhysicalDisplay.transform(Rect{clonedRoot->mScreenBounds});
             info.touchableRegion = info.touchableRegion.intersect(rect);
         }
     }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 36ae19c..14bb5b7 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -32,6 +32,7 @@
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
 #include <ui/Region.h>
+#include <ui/StretchEffect.h>
 #include <ui/Transform.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
@@ -323,6 +324,9 @@
         // An arbitrary threshold for the number of BufferlessSurfaceFrames in the state. Used to
         // trigger a warning if the number of SurfaceFrames crosses the threshold.
         static constexpr uint32_t kStateSurfaceFramesThreshold = 25;
+
+        // Stretch effect to apply to this layer
+        StretchEffect stretchEffect;
     };
 
     /*
@@ -909,7 +913,7 @@
     bool getPremultipledAlpha() const;
     void setInputInfo(const InputWindowInfo& info);
 
-    InputWindowInfo fillInputInfo();
+    InputWindowInfo fillInputInfo(const sp<DisplayDevice>& display);
     /**
      * Returns whether this layer has an explicitly set input-info.
      */
@@ -938,6 +942,9 @@
 
     bool backpressureEnabled() { return mDrawingState.flags & layer_state_t::eEnableBackpressure; }
 
+    bool setStretchEffect(const StretchEffect& effect);
+    StretchEffect getStretchEffect() const;
+
 protected:
     class SyncPoint {
     public:
@@ -1004,6 +1011,7 @@
     friend class TestableSurfaceFlinger;
     friend class RefreshRateSelectionTest;
     friend class SetFrameRateTest;
+    friend class TransactionFrameTracerTest;
     friend class TransactionSurfaceFrameTest;
 
     virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom);
@@ -1138,9 +1146,6 @@
     // Window types from WindowManager.LayoutParams
     const InputWindowInfo::Type mWindowType;
 
-    // Can only be accessed with the SF state lock held.
-    std::shared_ptr<frametimeline::SurfaceFrame> mSurfaceFrame;
-
     // The owner of the layer. If created from a non system process, it will be the calling uid.
     // If created from a system process, the value can be passed in.
     uid_t mOwnerUid;
@@ -1189,7 +1194,7 @@
     sp<Layer> getRootLayer();
 
     // Fills in the frame and transform info for the InputWindowInfo
-    void fillInputFrameInfo(InputWindowInfo& info);
+    void fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay);
 
     // Cached properties computed from drawing state
     // Effective transform taking into account parent transforms and any parent scaling, which is
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 49ffc81..b29c624 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -125,6 +125,9 @@
                                   GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
                                           GRALLOC_USAGE_HW_TEXTURE,
                                   "RefreshRateOverlayBuffer");
+        const status_t bufferStatus = buffer->initCheck();
+        LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
+                            bufferStatus);
         uint8_t* pixels;
         buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
         // Clear buffer content
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 9186538..09615f9 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -447,6 +447,9 @@
                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
         buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(),
                                    PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+        const status_t bufferStatus = buffer->initCheck();
+        LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d",
+                            bufferStatus);
     }
 
     const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
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..de11c16 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);
     }
 
@@ -64,9 +64,9 @@
 using RefreshRate = RefreshRateConfigs::RefreshRate;
 
 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());
+    return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
+                              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: %d, 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,52 @@
                   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);
+    // Reset the policy because the old one may no longer be valid.
+    mDisplayManagerPolicy = {};
+    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 +649,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 +707,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 +724,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 %d 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 +845,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..0e9eba7 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);
@@ -174,6 +174,8 @@
     // Stores the preferred refresh rate that an app should run at.
     // FrameRateOverride.refreshRateHz == 0 means no preference.
     void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesMutex);
+    // Retrieves the overridden refresh rate for a given uid.
+    std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex);
 
 private:
     friend class TestableScheduler;
@@ -227,16 +229,15 @@
     // 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);
 
-    std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex);
     impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const;
 
     // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
@@ -283,20 +284,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 4f93b89..4ee759f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -67,13 +67,14 @@
 #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/DynamicDisplayInfo.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/PixelFormat.h>
+#include <ui/StaticDisplayInfo.h>
 #include <utils/StopWatch.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
@@ -854,7 +855,8 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& displayToken, DisplayInfo* info) {
+status_t SurfaceFlinger::getStaticDisplayInfo(const sp<IBinder>& displayToken,
+                                              ui::StaticDisplayInfo* info) {
     if (!displayToken || !info) {
         return BAD_VALUE;
     }
@@ -875,7 +877,7 @@
     if (mEmulatedDisplayDensity) {
         info->density = mEmulatedDisplayDensity;
     } else {
-        info->density = info->connectionType == DisplayConnectionType::Internal
+        info->density = info->connectionType == ui::DisplayConnectionType::Internal
                 ? mInternalDisplayDensity
                 : FALLBACK_DENSITY;
     }
@@ -887,9 +889,9 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken,
-                                           Vector<DisplayConfig>* configs) {
-    if (!displayToken || !configs) {
+status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken,
+                                               ui::DynamicDisplayInfo* info) {
+    if (!displayToken || !info) {
         return BAD_VALUE;
     }
 
@@ -900,10 +902,19 @@
         return NAME_NOT_FOUND;
     }
 
-    configs->clear();
+    info->activeDisplayModeId = static_cast<int32_t>(display->getActiveMode()->getId().value());
+    if (display->isPrimary()) {
+        if (const auto mode = getDesiredActiveMode()) {
+            info->activeDisplayModeId = static_cast<int32_t>(mode->modeId.value());
+        }
+    }
 
-    for (const auto& mode : display->getSupportedModes()) {
-        DisplayConfig config;
+    const auto& supportedModes = display->getSupportedModes();
+    info->supportedDisplayModes.clear();
+    info->supportedDisplayModes.reserve(supportedModes.size());
+    for (const auto& mode : supportedModes) {
+        ui::DisplayMode outMode;
+        outMode.id = static_cast<int32_t>(mode->getId().value());
 
         auto width = mode->getWidth();
         auto height = mode->getHeight();
@@ -918,24 +929,24 @@
             std::swap(xDpi, yDpi);
         }
 
-        config.resolution = ui::Size(width, height);
+        outMode.resolution = ui::Size(width, height);
 
         if (mEmulatedDisplayDensity) {
-            config.xDpi = mEmulatedDisplayDensity;
-            config.yDpi = mEmulatedDisplayDensity;
+            outMode.xDpi = mEmulatedDisplayDensity;
+            outMode.yDpi = mEmulatedDisplayDensity;
         } else {
-            config.xDpi = xDpi;
-            config.yDpi = yDpi;
+            outMode.xDpi = xDpi;
+            outMode.yDpi = yDpi;
         }
 
         const nsecs_t period = mode->getVsyncPeriod();
-        config.refreshRate = Fps::fromPeriodNsecs(period).getValue();
+        outMode.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(outMode.refreshRate));
+        outMode.appVsyncOffset = vsyncConfigSet.late.appOffset;
+        outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset;
+        outMode.group = mode->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,11 +960,15 @@
         //
         // 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;
+        outMode.presentationDeadline = period - outMode.sfVsyncOffset + 1000000;
 
-        configs->push_back(config);
+        info->supportedDisplayModes.push_back(outMode);
     }
 
+    info->activeColorMode = display->getCompositionDisplay()->getState().colorMode;
+    info->supportedColorModes = getDisplayColorModes(display->getPhysicalId());
+
+    info->hdrCapabilities = display->getHdrCapabilities();
     return NO_ERROR;
 }
 
@@ -966,53 +981,27 @@
     return NO_ERROR;
 }
 
-int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) {
-    int activeConfig;
-    bool isPrimary;
-
-    {
-        Mutex::Autolock lock(mStateLock);
-
-        if (const auto display = getDisplayDeviceLocked(displayToken)) {
-            activeConfig = display->getActiveMode()->getId().value();
-            isPrimary = display->isPrimary();
-        } else {
-            ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
-            return NAME_NOT_FOUND;
-        }
-    }
-
-    if (isPrimary) {
-        if (const auto config = getDesiredActiveConfig()) {
-            return config->configId.value();
-        }
-    }
-
-    return activeConfig;
-}
-
-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 +1013,7 @@
         modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated);
 
         updatePhaseConfiguration(refreshRate.getFps());
-        mScheduler->setConfigChangePending(true);
+        mScheduler->setModeChangePending(true);
     }
 
     if (mRefreshRateOverlay) {
@@ -1032,7 +1021,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 +1031,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 +1056,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 +1070,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 = %d",
+              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 +1094,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 = %d",
+              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 %d(%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 +1167,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,42 +1177,23 @@
 
     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,
-                                              Vector<ColorMode>* outColorModes) {
-    if (!displayToken || !outColorModes) {
-        return BAD_VALUE;
-    }
-
-    std::vector<ColorMode> modes;
-    bool isInternalDisplay = false;
-    {
-        ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
-
-        const auto displayId = getPhysicalDisplayIdLocked(displayToken);
-        if (!displayId) {
-            return NAME_NOT_FOUND;
-        }
-
-        modes = getHwComposer().getColorModes(*displayId);
-        isInternalDisplay = displayId == getInternalDisplayIdLocked();
-    }
-    outColorModes->clear();
+std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) {
+    auto modes = getHwComposer().getColorModes(displayId);
+    bool isInternalDisplay = displayId == getInternalDisplayIdLocked();
 
     // If it's built-in display and the configuration claims it's not wide color capable,
     // filter out all wide color modes. The typical reason why this happens is that the
     // hardware is not good enough to support GPU composition of wide color, and thus the
     // OEMs choose to disable this capability.
     if (isInternalDisplay && !hasWideColorDisplay) {
-        std::remove_copy_if(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes),
-                            isWideColorMode);
-    } else {
-        std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes));
+        const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode);
+        modes.erase(newEnd, modes.end());
     }
 
-    return NO_ERROR;
+    return modes;
 }
 
 status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayToken,
@@ -1241,19 +1211,14 @@
     return NO_ERROR;
 }
 
-ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& displayToken) {
-    Mutex::Autolock lock(mStateLock);
-
-    if (const auto display = getDisplayDeviceLocked(displayToken)) {
-        return display->getCompositionDisplay()->getState().colorMode;
-    }
-    return static_cast<ColorMode>(BAD_VALUE);
-}
-
 status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
     schedule([=]() MAIN_THREAD {
-        Vector<ColorMode> modes;
-        getDisplayColorModes(displayToken, &modes);
+        const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+        if (!displayId) {
+            ALOGE("Invalid display token %p", displayToken.get());
+            return;
+        }
+        const auto modes = getDisplayColorModes(*displayId);
         bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes);
         if (mode < ColorMode::NATIVE || !exists) {
             ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p",
@@ -1350,28 +1315,6 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& displayToken,
-                                            HdrCapabilities* outCapabilities) const {
-    Mutex::Autolock lock(mStateLock);
-
-    const auto display = getDisplayDeviceLocked(displayToken);
-    if (!display) {
-        ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
-        return NAME_NOT_FOUND;
-    }
-
-    // At this point the DisplayDevice should already be set up,
-    // meaning the luminance information is already queried from
-    // hardware composer and stored properly.
-    const HdrCapabilities& capabilities = display->getHdrCapabilities();
-    *outCapabilities = HdrCapabilities(capabilities.getSupportedHdrTypes(),
-                                       capabilities.getDesiredMaxLuminance(),
-                                       capabilities.getDesiredMaxAverageLuminance(),
-                                       capabilities.getDesiredMinLuminance());
-
-    return NO_ERROR;
-}
-
 status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken,
                                                                ui::PixelFormat* outFormat,
                                                                ui::Dataspace* outDataspace,
@@ -1627,12 +1570,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 +1583,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 %d 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 +1772,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) {
@@ -1900,7 +1843,7 @@
         const bool tracePreComposition = mTracingEnabled && !mTracePostComposition;
         ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition);
 
-        mFrameTimeline->setSfWakeUp(vsyncId, frameStart, stats.vsyncPeriod);
+        mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod));
 
         refreshNeeded = handleMessageTransaction();
         refreshNeeded |= handleMessageInvalidate();
@@ -1920,7 +1863,7 @@
         mScheduler->chooseRefreshRateForContent();
     }
 
-    ON_MAIN_THREAD(performSetActiveConfig());
+    ON_MAIN_THREAD(performSetActiveMode());
 
     updateCursorAsync();
     updateInputFlinger();
@@ -2361,7 +2304,7 @@
 DisplayModes SurfaceFlinger::loadSupportedDisplayModes(PhysicalDisplayId displayId) const {
     const auto hwcModes = getHwComposer().getModes(displayId);
     DisplayModes modes;
-    size_t nextModeId = 0;
+    int32_t nextModeId = 0;
     for (const auto& hwcMode : hwcModes) {
         modes.push_back(DisplayMode::Builder(hwcMode.hwcId)
                                 .setId(DisplayModeId{nextModeId++})
@@ -2370,7 +2313,7 @@
                                 .setVsyncPeriod(hwcMode.vsyncPeriod)
                                 .setDpiX(hwcMode.dpiX)
                                 .setDpiY(hwcMode.dpiY)
-                                .setConfigGroup(hwcMode.configGroup)
+                                .setGroup(hwcMode.configGroup)
                                 .build());
     }
     return modes;
@@ -2391,7 +2334,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 +2618,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) {
@@ -2908,15 +2850,32 @@
     mInputWindowCommands.clear();
 }
 
+bool enablePerWindowInputRotation() {
+    static bool value =
+            android::base::GetBoolProperty("persist.debug.per_window_input_rotation", false);
+    return value;
+}
+
 void SurfaceFlinger::updateInputWindowInfo() {
     std::vector<InputWindowInfo> inputInfos;
 
     mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
-        if (layer->needsInputInfo()) {
-            // When calculating the screen bounds we ignore the transparent region since it may
-            // result in an unwanted offset.
-            inputInfos.push_back(layer->fillInputInfo());
+        if (!layer->needsInputInfo()) return;
+        sp<DisplayDevice> display;
+        if (enablePerWindowInputRotation()) {
+            for (const auto& pair : ON_MAIN_THREAD(mDisplays)) {
+                const auto& displayDevice = pair.second;
+                if (!displayDevice->getCompositionDisplay()
+                             ->belongsInOutput(layer->getLayerStack(),
+                                               layer->getPrimaryDisplayOnly())) {
+                    continue;
+                }
+                display = displayDevice;
+            }
         }
+        // When calculating the screen bounds we ignore the transparent region since it may
+        // result in an unwanted offset.
+        inputInfos.push_back(layer->fillInputInfo(display));
     });
 
     mInputFlinger->setInputWindows(inputInfos,
@@ -2935,8 +2894,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 +2954,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(
@@ -3953,6 +3911,11 @@
     if (what & layer_state_t::eAutoRefreshChanged) {
         layer->setAutoRefresh(s.autoRefresh);
     }
+    if (what & layer_state_t::eStretchChanged) {
+        if (layer->setStretchEffect(s.stretchEffect)) {
+            flags |= eTraversalNeeded;
+        }
+    }
     // This has to happen after we reparent children because when we reparent to null we remove
     // child layers from current state and remove its relative z. If the children are reparented in
     // the same transaction, then we have to make sure we reparent the children first so we do not
@@ -4543,8 +4506,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);
@@ -4965,8 +4928,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:
@@ -5008,13 +4971,14 @@
         // 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_STATIC_DISPLAY_INFO:
+        case GET_DYNAMIC_DISPLAY_INFO:
+        case GET_DISPLAY_MODES:
         case GET_DISPLAY_STATE:
         case GET_DISPLAY_STATS:
         case GET_SUPPORTED_FRAME_TIMESTAMPS:
@@ -5035,8 +4999,9 @@
         case CAPTURE_DISPLAY:
         case SET_DISPLAY_BRIGHTNESS:
         case SET_FRAME_TIMELINE_INFO:
-        // This is not sensitive information, so should not require permission control.
-        case GET_GPU_CONTEXT_PRIORITY: {
+        case GET_GPU_CONTEXT_PRIORITY:
+        case GET_EXTRA_BUFFER_COUNT: {
+            // This is not sensitive information, so should not require permission control.
             return OK;
         }
         case ADD_REGION_SAMPLING_LISTENER:
@@ -5388,7 +5353,7 @@
             }
             case 1035: {
                 const int modeId = data.readInt32();
-                mDebugDisplayConfigSetByBackdoor = false;
+                mDebugDisplayModeSetByBackdoor = false;
 
                 const auto displayId = getInternalDisplayId();
                 if (!displayId) {
@@ -5396,12 +5361,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;
             }
@@ -5480,14 +5445,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);
@@ -5851,6 +5815,10 @@
             getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
                                              static_cast<android_pixel_format>(reqPixelFormat),
                                              1 /* layerCount */, usage, "screenshot");
+
+    const status_t bufferStatus = buffer->initCheck();
+    LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d",
+                        bufferStatus);
     return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
                                false /* regionSampling */, grayscale, captureListener);
 }
@@ -6074,7 +6042,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);
@@ -6084,10 +6052,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;
@@ -6095,23 +6063,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;
     }
 
@@ -6126,40 +6093,39 @@
     }
     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 %d (%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 %d",
+              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: %d",
+                         preferredRefreshRate.getModeId().value());
     }
 
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(
-        const sp<IBinder>& displayToken, int32_t defaultConfig, bool allowGroupSwitching,
+status_t SurfaceFlinger::setDesiredDisplayModeSpecs(
+        const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode, bool allowGroupSwitching,
         float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
         float appRequestRefreshRateMax) {
     ATRACE_CALL();
@@ -6171,34 +6137,37 @@
     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,
-        float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
-        float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) {
+status_t SurfaceFlinger::getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+                                                    ui::DisplayModeId* 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;
     }
@@ -6212,7 +6181,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();
@@ -6223,7 +6192,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();
@@ -6353,16 +6322,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) {
@@ -6402,7 +6370,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");
         }
     }));
@@ -6463,6 +6431,25 @@
     return getRenderEngine().getContextPriority();
 }
 
+int SurfaceFlinger::calculateExtraBufferCount(Fps maxSupportedRefreshRate,
+                                              std::chrono::nanoseconds presentLatency) {
+    auto pipelineDepth = presentLatency.count() / maxSupportedRefreshRate.getPeriodNsecs();
+    if (presentLatency.count() % maxSupportedRefreshRate.getPeriodNsecs()) {
+        pipelineDepth++;
+    }
+    return std::max(0ll, pipelineDepth - 2);
+}
+
+status_t SurfaceFlinger::getExtraBufferCount(int* extraBuffers) const {
+    const auto maxSupportedRefreshRate = mRefreshRateConfigs->getSupportedRefreshRateRange().max;
+    const auto vsyncConfig =
+            mVsyncConfiguration->getConfigsForRefreshRate(maxSupportedRefreshRate).late;
+    const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration;
+
+    *extraBuffers = calculateExtraBufferCount(maxSupportedRefreshRate, presentLatency);
+    return NO_ERROR;
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f924f45..21cd2a5 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -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;
         }
     };
 
@@ -552,14 +552,14 @@
                            const sp<IScreenCaptureListener>& captureListener) override;
 
     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 getDisplayColorModes(const sp<IBinder>& displayToken, Vector<ui::ColorMode>*) override;
+    status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*)
+            EXCLUDES(mStateLock) override;
+    status_t getStaticDisplayInfo(const sp<IBinder>& displayToken, ui::StaticDisplayInfo*)
+            EXCLUDES(mStateLock) override;
+    status_t getDynamicDisplayInfo(const sp<IBinder>& displayToken, ui::DynamicDisplayInfo*)
+            EXCLUDES(mStateLock) override;
     status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
                                        ui::DisplayPrimaries&) override;
-    ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken) override;
     status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
     status_t getAutoLowLatencyModeSupport(const sp<IBinder>& displayToken,
                                           bool* outSupported) const override;
@@ -570,8 +570,6 @@
     void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
     status_t clearAnimationFrameStats() override;
     status_t getAnimationFrameStats(FrameStats* outStats) const override;
-    status_t getHdrCapabilities(const sp<IBinder>& displayToken,
-                                HdrCapabilities* outCapabilities) const override;
     status_t enableVSyncInjections(bool enable) override;
     status_t injectVSync(nsecs_t when) override;
     status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override;
@@ -594,17 +592,18 @@
     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,
+                                        ui::DisplayModeId displayModeId, bool allowGroupSwitching,
+                                        float primaryRefreshRateMin, float primaryRefreshRateMax,
+                                        float appRequestRefreshRateMin,
+                                        float appRequestRefreshRateMax) override;
+    status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+                                        ui::DisplayModeId* outDefaultMode,
+                                        bool* outAllowGroupSwitching,
+                                        float* outPrimaryRefreshRateMin,
+                                        float* outPrimaryRefreshRateMax,
+                                        float* outAppRequestRefreshRateMin,
+                                        float* outAppRequestRefreshRateMax) override;
     status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
                                          bool* outSupport) const override;
     status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) override;
@@ -623,6 +622,8 @@
 
     int getGPUContextPriority() override;
 
+    status_t getExtraBufferCount(int* extraBuffers) const override;
+
     // Implements IBinder::DeathRecipient.
     void binderDied(const wp<IBinder>& who) override;
 
@@ -649,7 +650,7 @@
     // Toggles hardware VSYNC by calling into HWC.
     void setVsyncEnabled(bool) override;
     // Initiates a refresh rate change to be applied on invalidate.
-    void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ConfigEvent) override;
+    void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override;
     // Forces full composition on all displays without resetting the scheduler idle timer.
     void repaintEverythingForHWC() override;
     // Called when kernel idle timer has expired. Used to update the refresh rate overlay.
@@ -677,24 +678,24 @@
 
     // Called on the main thread in response to initializeDisplays()
     void onInitializeDisplays() REQUIRES(mStateLock);
-    // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
-    void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
-    status_t setActiveConfig(const sp<IBinder>& displayToken, int id);
-    // Once HWC has returned the present fence, this sets the active config and a new refresh
+    // Sets the desired active mode bit. It obtains the lock, and sets mDesiredActiveMode.
+    void setDesiredActiveMode(const ActiveModeInfo& info) REQUIRES(mStateLock);
+    status_t setActiveMode(const sp<IBinder>& displayToken, int id);
+    // Once HWC has returned the present fence, this sets the active mode and a new refresh
     // rate in SF.
-    void setActiveConfigInternal() REQUIRES(mStateLock);
-    // Calls to setActiveConfig on the main thread if there is a pending config
+    void setActiveModeInternal() REQUIRES(mStateLock);
+    // Calls to setActiveMode on the main thread if there is a pending mode change
     // that needs to be applied.
-    void performSetActiveConfig() REQUIRES(mStateLock);
-    void clearDesiredActiveConfigState() REQUIRES(mStateLock) EXCLUDES(mActiveConfigLock);
-    // Called when active config is no longer is progress
-    void desiredActiveConfigChangeDone() REQUIRES(mStateLock);
+    void performSetActiveMode() REQUIRES(mStateLock);
+    void clearDesiredActiveModeState() REQUIRES(mStateLock) EXCLUDES(mActiveModeLock);
+    // Called when active mode is no longer is progress
+    void desiredActiveModeChangeDone() REQUIRES(mStateLock);
     // Called on the main thread in response to setPowerMode()
     void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
             REQUIRES(mStateLock);
 
-    // Sets the desired display configs.
-    status_t setDesiredDisplayConfigSpecsInternal(
+    // Sets the desired display mode specs.
+    status_t setDesiredDisplayModeSpecsInternal(
             const sp<DisplayDevice>& display,
             const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
             EXCLUDES(mStateLock);
@@ -929,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.
@@ -1047,12 +1048,18 @@
      * 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;
     }
 
+    std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId displayId)
+            REQUIRES(mStateLock);
+
+    static int calculateExtraBufferCount(Fps maxSupportedRefreshRate,
+                                         std::chrono::nanoseconds presentLatency);
+
     sp<StartPropertySetThread> mStartPropertySetThread;
     surfaceflinger::Factory& mFactory;
 
@@ -1246,18 +1253,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;
@@ -1281,8 +1288,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/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 61005c9..b0413f1 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -499,6 +499,9 @@
     if (state.what & layer_state_t::eShadowRadiusChanged) {
         addShadowRadiusLocked(transaction, layerId, state.shadowRadius);
     }
+    if (state.what & layer_state_t::eStretchChanged) {
+        ALOGW("SurfaceInterceptor not implemented for eStretchChanged");
+    }
 }
 
 void SurfaceInterceptor::addDisplayChangesLocked(Transaction* transaction,
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index 1d1f0c5..b4d8a9a 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -71,12 +71,14 @@
 }
 
 void SurfaceTracing::notify(const char* where) {
+    std::scoped_lock lock(mTraceLock);
     if (mEnabled) {
         runner->notify(where);
     }
 }
 
 void SurfaceTracing::notifyLocked(const char* where) {
+    std::scoped_lock lock(mTraceLock);
     if (mEnabled) {
         runner->notifyLocked(where);
     }
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 497ebd3..15a503d 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -81,8 +81,8 @@
 
     SurfaceFlinger& mFlinger;
     mutable std::mutex mTraceLock;
-    bool mEnabled = false;
-    std::unique_ptr<Runner> runner;
+    bool mEnabled GUARDED_BY(mTraceLock) = false;
+    std::unique_ptr<Runner> runner GUARDED_BY(mTraceLock);
 
     struct Config {
         uint32_t flags = TRACE_CRITICAL | TRACE_INPUT | TRACE_SYNC;
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
index 0a23da2..62fddb4 100644
--- a/services/surfaceflinger/TimeStats/Android.bp
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library {
     name: "libtimestats",
     srcs: [
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 5d387d6..100354a 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -105,53 +105,64 @@
 AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    if (mTimeStats.statsStart == 0) {
+    if (mTimeStats.statsStartLegacy == 0) {
         return AStatsManager_PULL_SKIP;
     }
     flushPowerTimeLocked();
 
-    AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
-    mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
-    mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount);
-    std::string frameDurationBytes =
-            histogramToProtoByteString(mTimeStats.frameDuration.hist, mMaxPulledHistogramBuckets);
-    mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
-                                             frameDurationBytes.size());
-    std::string renderEngineTimingBytes =
-            histogramToProtoByteString(mTimeStats.renderEngineTiming.hist,
-                                       mMaxPulledHistogramBuckets);
-    mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)renderEngineTimingBytes.c_str(),
-                                             renderEngineTimingBytes.size());
+    for (const auto& globalSlice : mTimeStats.stats) {
+        AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
+        mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+        mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFramesLegacy);
+        mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFramesLegacy);
+        mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFramesLegacy);
+        mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTimeLegacy);
+        mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresentLegacy.totalTime());
+        mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCountLegacy);
+        std::string frameDurationBytes =
+                histogramToProtoByteString(mTimeStats.frameDurationLegacy.hist,
+                                           mMaxPulledHistogramBuckets);
+        mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
+                                                 frameDurationBytes.size());
+        std::string renderEngineTimingBytes =
+                histogramToProtoByteString(mTimeStats.renderEngineTimingLegacy.hist,
+                                           mMaxPulledHistogramBuckets);
+        mStatsDelegate->statsEventWriteByteArray(event,
+                                                 (const uint8_t*)renderEngineTimingBytes.c_str(),
+                                                 renderEngineTimingBytes.size());
 
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalFrames);
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalJankyFrames);
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFLongCpu);
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFLongGpu);
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFUnattributed);
-    mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalAppUnattributed);
+        mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalFrames);
+        mStatsDelegate->statsEventWriteInt32(event,
+                                             globalSlice.second.jankPayload.totalJankyFrames);
+        mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongCpu);
+        mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongGpu);
+        mStatsDelegate->statsEventWriteInt32(event,
+                                             globalSlice.second.jankPayload.totalSFUnattributed);
+        mStatsDelegate->statsEventWriteInt32(event,
+                                             globalSlice.second.jankPayload.totalAppUnattributed);
+        mStatsDelegate->statsEventWriteInt32(event,
+                                             globalSlice.second.jankPayload.totalSFScheduling);
+        mStatsDelegate->statsEventWriteInt32(event,
+                                             globalSlice.second.jankPayload.totalSFPredictionError);
+        mStatsDelegate->statsEventWriteInt32(event,
+                                             globalSlice.second.jankPayload.totalAppBufferStuffing);
+        mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.displayRefreshRateBucket);
+        std::string sfDeadlineMissedBytes =
+                histogramToProtoByteString(globalSlice.second.displayDeadlineDeltas.hist,
+                                           mMaxPulledHistogramBuckets);
+        mStatsDelegate->statsEventWriteByteArray(event,
+                                                 (const uint8_t*)sfDeadlineMissedBytes.c_str(),
+                                                 sfDeadlineMissedBytes.size());
+        std::string sfPredictionErrorBytes =
+                histogramToProtoByteString(globalSlice.second.displayPresentDeltas.hist,
+                                           mMaxPulledHistogramBuckets);
+        mStatsDelegate->statsEventWriteByteArray(event,
+                                                 (const uint8_t*)sfPredictionErrorBytes.c_str(),
+                                                 sfPredictionErrorBytes.size());
+        mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.renderRateBucket);
+        mStatsDelegate->statsEventBuild(event);
+    }
 
-    // TODO: populate these with real values
-    mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling
-    mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error
-    mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing
-    mStatsDelegate->statsEventWriteInt32(event, 0); // display_refresh_rate_bucket
-    std::string sfDeadlineMissedBytes =
-            histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
-                                       mMaxPulledHistogramBuckets);
-    mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)sfDeadlineMissedBytes.c_str(),
-                                             sfDeadlineMissedBytes.size()); // sf_deadline_misses
-    std::string sfPredictionErrorBytes =
-            histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
-                                       mMaxPulledHistogramBuckets);
-    mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)sfPredictionErrorBytes.c_str(),
-                                             sfPredictionErrorBytes.size()); // sf_prediction_errors
-    mStatsDelegate->statsEventWriteInt32(event, 0); // render_rate_bucket
-    mStatsDelegate->statsEventBuild(event);
     clearGlobalLocked();
 
     return AStatsManager_PULL_SUCCESS;
@@ -160,9 +171,18 @@
 AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventList* data) {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    std::vector<TimeStatsHelper::TimeStatsLayer const*> dumpStats;
-    for (const auto& ele : mTimeStats.stats) {
-        dumpStats.push_back(&ele.second);
+    std::vector<TimeStatsHelper::TimeStatsLayer*> dumpStats;
+    uint32_t numLayers = 0;
+    for (const auto& globalSlice : mTimeStats.stats) {
+        numLayers += globalSlice.second.stats.size();
+    }
+
+    dumpStats.reserve(numLayers);
+
+    for (auto& globalSlice : mTimeStats.stats) {
+        for (auto& layerSlice : globalSlice.second.stats) {
+            dumpStats.push_back(&layerSlice.second);
+        }
     }
 
     std::sort(dumpStats.begin(), dumpStats.end(),
@@ -175,7 +195,7 @@
         dumpStats.resize(mMaxPulledLayers);
     }
 
-    for (const auto& layer : dumpStats) {
+    for (auto& layer : dumpStats) {
         AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
         mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_LAYER_INFO);
         mStatsDelegate->statsEventWriteString8(event, layer->layerName.c_str());
@@ -203,22 +223,21 @@
         mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFLongGpu);
         mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFUnattributed);
         mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppUnattributed);
-
-        // TODO: populate these with real values
-        mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling
-        mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error
-        mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing
-        mStatsDelegate->statsEventWriteInt32(event, 0); // display_refresh_rate_bucket
-        mStatsDelegate->statsEventWriteInt32(event, 0); // render_rate_bucket
+        mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFScheduling);
+        mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFPredictionError);
+        mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppBufferStuffing);
+        mStatsDelegate->statsEventWriteInt32(
+                event, layer->displayRefreshRateBucket); // display_refresh_rate_bucket
+        mStatsDelegate->statsEventWriteInt32(event, layer->renderRateBucket); // render_rate_bucket
         std::string frameRateVoteBytes = frameRateVoteToProtoByteString(0.0, 0, 0);
         mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameRateVoteBytes.c_str(),
                                                  frameRateVoteBytes.size()); // set_frame_rate_vote
         std::string appDeadlineMissedBytes =
-                histogramToProtoByteString(std::unordered_map<int32_t, int32_t>(),
+                histogramToProtoByteString(layer->deltas["appDeadlineDeltas"].hist,
                                            mMaxPulledHistogramBuckets);
-        mStatsDelegate
-                ->statsEventWriteByteArray(event, (const uint8_t*)appDeadlineMissedBytes.c_str(),
-                                           appDeadlineMissedBytes.size()); // app_deadline_misses
+        mStatsDelegate->statsEventWriteByteArray(event,
+                                                 (const uint8_t*)appDeadlineMissedBytes.c_str(),
+                                                 appDeadlineMissedBytes.size());
 
         mStatsDelegate->statsEventBuild(event);
     }
@@ -310,7 +329,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.totalFrames++;
+    mTimeStats.totalFramesLegacy++;
 }
 
 void TimeStats::incrementMissedFrames() {
@@ -319,7 +338,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.missedFrames++;
+    mTimeStats.missedFramesLegacy++;
 }
 
 void TimeStats::incrementClientCompositionFrames() {
@@ -328,7 +347,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.clientCompositionFrames++;
+    mTimeStats.clientCompositionFramesLegacy++;
 }
 
 void TimeStats::incrementClientCompositionReusedFrames() {
@@ -337,7 +356,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.clientCompositionReusedFrames++;
+    mTimeStats.clientCompositionReusedFramesLegacy++;
 }
 
 void TimeStats::incrementRefreshRateSwitches() {
@@ -346,7 +365,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.refreshRateSwitches++;
+    mTimeStats.refreshRateSwitchesLegacy++;
 }
 
 void TimeStats::incrementCompositionStrategyChanges() {
@@ -355,7 +374,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.compositionStrategyChanges++;
+    mTimeStats.compositionStrategyChangesLegacy++;
 }
 
 void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
@@ -364,8 +383,8 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    mTimeStats.displayEventConnectionsCount =
-            std::max(mTimeStats.displayEventConnectionsCount, count);
+    mTimeStats.displayEventConnectionsCountLegacy =
+            std::max(mTimeStats.displayEventConnectionsCountLegacy, count);
 }
 
 static int32_t msBetween(nsecs_t start, nsecs_t end) {
@@ -381,7 +400,7 @@
 
     std::lock_guard<std::mutex> lock(mMutex);
     if (mPowerTime.powerMode == PowerMode::ON) {
-        mTimeStats.frameDuration.insert(msBetween(startTime, endTime));
+        mTimeStats.frameDurationLegacy.insert(msBetween(startTime, endTime));
     }
 }
 
@@ -444,12 +463,22 @@
     return true;
 }
 
-void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId) {
+static int32_t clampToSmallestBucket(Fps fps, size_t bucketWidth) {
+    return (fps.getIntValue() / bucketWidth) * bucketWidth;
+}
+
+void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
+                                                   std::optional<Fps> renderRate) {
     ATRACE_CALL();
 
     LayerRecord& layerRecord = mTimeStatsTracker[layerId];
     TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
     std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
+    const int32_t refreshRateBucket =
+            clampToSmallestBucket(displayRefreshRate, REFRESH_RATE_BUCKET_WIDTH);
+    const int32_t renderRateBucket =
+            clampToSmallestBucket(renderRate ? *renderRate : displayRefreshRate,
+                                  RENDER_RATE_BUCKET_WIDTH);
     while (!timeRecords.empty()) {
         if (!recordReadyLocked(layerId, &timeRecords[0])) break;
         ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerId,
@@ -458,11 +487,21 @@
         if (prevTimeRecord.ready) {
             uid_t uid = layerRecord.uid;
             const std::string& layerName = layerRecord.layerName;
-            if (!mTimeStats.stats.count({uid, layerName})) {
-                mTimeStats.stats[{uid, layerName}].uid = uid;
-                mTimeStats.stats[{uid, layerName}].layerName = layerName;
+            TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
+            if (!mTimeStats.stats.count(timelineKey)) {
+                mTimeStats.stats[timelineKey].key = timelineKey;
             }
-            TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[{uid, layerName}];
+
+            TimeStatsHelper::TimelineStats& displayStats = mTimeStats.stats[timelineKey];
+
+            TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName};
+            if (!displayStats.stats.count(layerKey)) {
+                displayStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
+                displayStats.stats[layerKey].renderRateBucket = renderRateBucket;
+                displayStats.stats[layerKey].uid = uid;
+                displayStats.stats[layerKey].layerName = layerName;
+            }
+            TimeStatsHelper::TimeStatsLayer& timeStatsLayer = displayStats.stats[layerKey];
             timeStatsLayer.totalFrames++;
             timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
             timeStatsLayer.lateAcquireFrames += layerRecord.lateAcquireFrames;
@@ -524,8 +563,16 @@
 }
 
 bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName) {
-    return mTimeStats.stats.count({uid, layerName}) > 0 ||
-            mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
+    uint32_t layerRecords = 0;
+    for (const auto& record : mTimeStats.stats) {
+        if (record.second.stats.count({uid, layerName}) > 0) {
+            return true;
+        }
+
+        layerRecords += record.second.stats.size();
+    }
+
+    return mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
 }
 
 void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
@@ -676,7 +723,8 @@
     }
 }
 
-void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) {
+void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
+                               Fps displayRefreshRate, std::optional<Fps> renderRate) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
@@ -695,11 +743,12 @@
         layerRecord.waitData++;
     }
 
-    flushAvailableRecordsToStatsLocked(layerId);
+    flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate);
 }
 
 void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber,
-                                const std::shared_ptr<FenceTime>& presentFence) {
+                                const std::shared_ptr<FenceTime>& presentFence,
+                                Fps displayRefreshRate, std::optional<Fps> renderRate) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
@@ -719,16 +768,18 @@
         layerRecord.waitData++;
     }
 
-    flushAvailableRecordsToStatsLocked(layerId);
+    flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate);
 }
 
+static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL |
+        JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed |
+        JankType::AppDeadlineMissed | JankType::PredictionError |
+        JankType::SurfaceFlingerScheduling | JankType::BufferStuffing;
+
 template <class T>
 static void updateJankPayload(T& t, int32_t reasons) {
     t.jankPayload.totalFrames++;
 
-    static const constexpr int32_t kValidJankyReason = JankType::SurfaceFlingerCpuDeadlineMissed |
-            JankType::SurfaceFlingerGpuDeadlineMissed | JankType::AppDeadlineMissed |
-            JankType::DisplayHAL;
     if (reasons & kValidJankyReason) {
         t.jankPayload.totalJankyFrames++;
         if ((reasons & JankType::SurfaceFlingerCpuDeadlineMissed) != 0) {
@@ -743,19 +794,19 @@
         if ((reasons & JankType::AppDeadlineMissed) != 0) {
             t.jankPayload.totalAppUnattributed++;
         }
+        if ((reasons & JankType::PredictionError) != 0) {
+            t.jankPayload.totalSFPredictionError++;
+        }
+        if ((reasons & JankType::SurfaceFlingerScheduling) != 0) {
+            t.jankPayload.totalSFScheduling++;
+        }
+        if ((reasons & JankType::BufferStuffing) != 0) {
+            t.jankPayload.totalAppBufferStuffing++;
+        }
     }
 }
 
-void TimeStats::incrementJankyFrames(int32_t reasons) {
-    if (!mEnabled.load()) return;
-
-    ATRACE_CALL();
-    std::lock_guard<std::mutex> lock(mMutex);
-
-    updateJankPayload<TimeStatsHelper::TimeStatsGlobal>(mTimeStats, reasons);
-}
-
-void TimeStats::incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) {
+void TimeStats::incrementJankyFrames(const JankyFramesInfo& info) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
@@ -772,17 +823,44 @@
     // TimeStats will flush the first present fence for a layer *before* FrameTimeline does so that
     // the first jank record is not dropped.
 
-    bool useDefaultLayerKey = false;
     static const std::string kDefaultLayerName = "none";
-    if (!mTimeStats.stats.count({uid, layerName})) {
-        mTimeStats.stats[{uid, kDefaultLayerName}].uid = uid;
-        mTimeStats.stats[{uid, kDefaultLayerName}].layerName = kDefaultLayerName;
-        useDefaultLayerKey = true;
+
+    const int32_t refreshRateBucket =
+            clampToSmallestBucket(info.refreshRate, REFRESH_RATE_BUCKET_WIDTH);
+    const int32_t renderRateBucket =
+            clampToSmallestBucket(info.renderRate ? *info.renderRate : info.refreshRate,
+                                  RENDER_RATE_BUCKET_WIDTH);
+    const TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket};
+
+    if (!mTimeStats.stats.count(timelineKey)) {
+        mTimeStats.stats[timelineKey].key = timelineKey;
     }
 
-    TimeStatsHelper::TimeStatsLayer& timeStatsLayer =
-            mTimeStats.stats[{uid, useDefaultLayerKey ? kDefaultLayerName : layerName}];
-    updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, reasons);
+    TimeStatsHelper::TimelineStats& timelineStats = mTimeStats.stats[timelineKey];
+
+    updateJankPayload<TimeStatsHelper::TimelineStats>(timelineStats, info.reasons);
+
+    TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName};
+    if (!timelineStats.stats.count(layerKey)) {
+        layerKey = {info.uid, kDefaultLayerName};
+        timelineStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
+        timelineStats.stats[layerKey].renderRateBucket = renderRateBucket;
+        timelineStats.stats[layerKey].uid = info.uid;
+        timelineStats.stats[layerKey].layerName = kDefaultLayerName;
+    }
+
+    TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timelineStats.stats[layerKey];
+    updateJankPayload<TimeStatsHelper::TimeStatsLayer>(timeStatsLayer, info.reasons);
+
+    if (info.reasons & kValidJankyReason) {
+        // TimeStats Histograms only retain positive values, so we don't need to check if these
+        // deadlines were really missed if we know that the frame had jank, since deadlines
+        // that were met will be dropped.
+        timelineStats.displayDeadlineDeltas.insert(static_cast<int32_t>(info.displayDeadlineDelta));
+        timelineStats.displayPresentDeltas.insert(static_cast<int32_t>(info.displayPresentJitter));
+        timeStatsLayer.deltas["appDeadlineDeltas"].insert(
+                static_cast<int32_t>(info.appDeadlineDelta));
+    }
 }
 
 void TimeStats::onDestroy(int32_t layerId) {
@@ -823,7 +901,7 @@
 
     switch (mPowerTime.powerMode) {
         case PowerMode::ON:
-            mTimeStats.displayOnTime += elapsedTime;
+            mTimeStats.displayOnTimeLegacy += elapsedTime;
             break;
         case PowerMode::OFF:
         case PowerMode::DOZE:
@@ -852,10 +930,10 @@
 
 void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) {
     std::lock_guard<std::mutex> lock(mMutex);
-    if (mTimeStats.refreshRateStats.count(fps)) {
-        mTimeStats.refreshRateStats[fps] += duration;
+    if (mTimeStats.refreshRateStatsLegacy.count(fps)) {
+        mTimeStats.refreshRateStatsLegacy[fps] += duration;
     } else {
-        mTimeStats.refreshRateStats.insert({fps, duration});
+        mTimeStats.refreshRateStatsLegacy.insert({fps, duration});
     }
 }
 
@@ -881,7 +959,7 @@
                     msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
             ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]",
                   presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime);
-            mTimeStats.presentToPresent.insert(presentToPresentMs);
+            mTimeStats.presentToPresentLegacy.insert(presentToPresentMs);
         }
 
         mGlobalRecord.prevPresentTime = curPresentTime;
@@ -908,7 +986,7 @@
         }
 
         const int32_t renderEngineMs = msBetween(duration.startTime, endNs);
-        mTimeStats.renderEngineTiming.insert(renderEngineMs);
+        mTimeStats.renderEngineTimingLegacy.insert(renderEngineMs);
 
         mGlobalRecord.renderEngineDurations.pop_front();
     }
@@ -951,7 +1029,7 @@
 
     std::lock_guard<std::mutex> lock(mMutex);
     mEnabled.store(true);
-    mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
+    mTimeStats.statsStartLegacy = static_cast<int64_t>(std::time(0));
     mPowerTime.prevTime = systemTime();
     ALOGD("Enabled");
 }
@@ -964,7 +1042,7 @@
     std::lock_guard<std::mutex> lock(mMutex);
     flushPowerTimeLocked();
     mEnabled.store(false);
-    mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+    mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
     ALOGD("Disabled");
 }
 
@@ -977,21 +1055,20 @@
 void TimeStats::clearGlobalLocked() {
     ATRACE_CALL();
 
-    mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
-    mTimeStats.statsEnd = 0;
-    mTimeStats.totalFrames = 0;
-    mTimeStats.missedFrames = 0;
-    mTimeStats.clientCompositionFrames = 0;
-    mTimeStats.clientCompositionReusedFrames = 0;
-    mTimeStats.refreshRateSwitches = 0;
-    mTimeStats.compositionStrategyChanges = 0;
-    mTimeStats.displayEventConnectionsCount = 0;
-    mTimeStats.displayOnTime = 0;
-    mTimeStats.presentToPresent.hist.clear();
-    mTimeStats.frameDuration.hist.clear();
-    mTimeStats.renderEngineTiming.hist.clear();
-    mTimeStats.jankPayload = TimeStatsHelper::JankPayload();
-    mTimeStats.refreshRateStats.clear();
+    mTimeStats.statsStartLegacy = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
+    mTimeStats.statsEndLegacy = 0;
+    mTimeStats.totalFramesLegacy = 0;
+    mTimeStats.missedFramesLegacy = 0;
+    mTimeStats.clientCompositionFramesLegacy = 0;
+    mTimeStats.clientCompositionReusedFramesLegacy = 0;
+    mTimeStats.refreshRateSwitchesLegacy = 0;
+    mTimeStats.compositionStrategyChangesLegacy = 0;
+    mTimeStats.displayEventConnectionsCountLegacy = 0;
+    mTimeStats.displayOnTimeLegacy = 0;
+    mTimeStats.presentToPresentLegacy.hist.clear();
+    mTimeStats.frameDurationLegacy.hist.clear();
+    mTimeStats.renderEngineTimingLegacy.hist.clear();
+    mTimeStats.refreshRateStatsLegacy.clear();
     mPowerTime.prevTime = systemTime();
     mGlobalRecord.prevPresentTime = 0;
     mGlobalRecord.presentFences.clear();
@@ -1014,11 +1091,11 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (mTimeStats.statsStart == 0) {
+    if (mTimeStats.statsStartLegacy == 0) {
         return;
     }
 
-    mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+    mTimeStats.statsEndLegacy = static_cast<int64_t>(std::time(0));
 
     flushPowerTimeLocked();
 
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index df40ef6..fd112b9 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -27,12 +27,13 @@
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
 
+#include <../Fps.h>
+#include <gui/JankInfo.h>
 #include <stats_event.h>
 #include <stats_pull_atom_callback.h>
 #include <statslog.h>
 #include <timestatsproto/TimeStatsHelper.h>
 #include <timestatsproto/TimeStatsProtoHeader.h>
-#include <gui/JankInfo.h>
 #include <ui/FenceTime.h>
 #include <utils/String16.h>
 #include <utils/Vector.h>
@@ -108,23 +109,60 @@
                                  const std::shared_ptr<FenceTime>& acquireFence) = 0;
     // SetPresent{Time, Fence} are not expected to be called in the critical
     // rendering path, as they flush prior fences if those fences have fired.
-    virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) = 0;
+    virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
+                                Fps displayRefreshRate, std::optional<Fps> renderRate) = 0;
     virtual void setPresentFence(int32_t layerId, uint64_t frameNumber,
-                                 const std::shared_ptr<FenceTime>& presentFence) = 0;
+                                 const std::shared_ptr<FenceTime>& presentFence,
+                                 Fps displayRefreshRate, std::optional<Fps> renderRate) = 0;
 
-    // Increments janky frames, tracked globally. Because FrameTimeline is the infrastructure
-    // responsible for computing jank in the system, this is expected to be called from
-    // FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there are no
-    // jank reasons, then total frames are incremented but jank is not, for accurate accounting of
-    // janky frames.
-    virtual void incrementJankyFrames(int32_t reasons) = 0;
-    // Increments janky frames, blamed to the provided {uid, layerName} key, with JankMetadata as
-    // supplementary reasons for the jank. Because FrameTimeline is the infrastructure responsible
-    // for computing jank in the system, this is expected to be called from FrameTimeline, rather
-    // than directly from SurfaceFlinger or individual layers.
-    // If there are no jank reasons, then total frames are incremented but jank is not, for accurate
+    // Increments janky frames, blamed to the provided {refreshRate, renderRate, uid, layerName}
+    // key, with JankMetadata as supplementary reasons for the jank. Because FrameTimeline is the
+    // infrastructure responsible for computing jank in the system, this is expected to be called
+    // from FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there
+    // are no jank reasons, then total frames are incremented but jank is not, for accurate
     // accounting of janky frames.
-    virtual void incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) = 0;
+    // displayDeadlineDelta, displayPresentJitter, and appDeadlineDelta are also provided in order
+    // to provide contextual information about a janky frame. These values may only be uploaded if
+    // there was an associated valid jank reason, and they must be positive. When these frame counts
+    // are incremented, these are also aggregated into a global reporting packet to help with data
+    // validation and assessing of overall device health.
+    struct JankyFramesInfo {
+        Fps refreshRate;
+        std::optional<Fps> renderRate;
+        uid_t uid = 0;
+        std::string layerName;
+        int32_t reasons = 0;
+        nsecs_t displayDeadlineDelta = 0;
+        nsecs_t displayPresentJitter = 0;
+        nsecs_t appDeadlineDelta = 0;
+
+        bool operator==(const JankyFramesInfo& o) const {
+            return Fps::EqualsInBuckets{}(refreshRate, o.refreshRate) &&
+                    ((renderRate == std::nullopt && o.renderRate == std::nullopt) ||
+                     (renderRate != std::nullopt && o.renderRate != std::nullopt &&
+                      Fps::EqualsInBuckets{}(*renderRate, *o.renderRate))) &&
+                    uid == o.uid && layerName == o.layerName && reasons == o.reasons &&
+                    displayDeadlineDelta == o.displayDeadlineDelta &&
+                    displayPresentJitter == o.displayPresentJitter &&
+                    appDeadlineDelta == o.appDeadlineDelta;
+        }
+
+        friend std::ostream& operator<<(std::ostream& os, const JankyFramesInfo& info) {
+            os << "JankyFramesInfo {";
+            os << "\n    .refreshRate = " << info.refreshRate;
+            os << "\n    .renderRate = "
+               << (info.renderRate ? to_string(*info.renderRate) : "nullopt");
+            os << "\n    .uid = " << info.uid;
+            os << "\n    .layerName = " << info.layerName;
+            os << "\n    .reasons = " << info.reasons;
+            os << "\n    .displayDeadlineDelta = " << info.displayDeadlineDelta;
+            os << "\n    .displayPresentJitter = " << info.displayPresentJitter;
+            os << "\n    .appDeadlineDelta = " << info.appDeadlineDelta;
+            return os << "\n}";
+        }
+    };
+
+    virtual void incrementJankyFrames(const JankyFramesInfo& info) = 0;
     // Clean up the layer record
     virtual void onDestroy(int32_t layerId) = 0;
     // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
@@ -268,11 +306,13 @@
     void setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) override;
     void setAcquireFence(int32_t layerId, uint64_t frameNumber,
                          const std::shared_ptr<FenceTime>& acquireFence) override;
-    void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) override;
+    void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
+                        Fps displayRefreshRate, std::optional<Fps> renderRate) override;
     void setPresentFence(int32_t layerId, uint64_t frameNumber,
-                         const std::shared_ptr<FenceTime>& presentFence) override;
-    void incrementJankyFrames(int32_t reasons) override;
-    void incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) override;
+                         const std::shared_ptr<FenceTime>& presentFence, Fps displayRefreshRate,
+                         std::optional<Fps> renderRate) override;
+
+    void incrementJankyFrames(const JankyFramesInfo& info) override;
     // Clean up the layer record
     void onDestroy(int32_t layerId) override;
     // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
@@ -293,7 +333,8 @@
     AStatsManager_PullAtomCallbackReturn populateGlobalAtom(AStatsEventList* data);
     AStatsManager_PullAtomCallbackReturn populateLayerAtom(AStatsEventList* data);
     bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord);
-    void flushAvailableRecordsToStatsLocked(int32_t layerId);
+    void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
+                                            std::optional<Fps> renderRate);
     void flushPowerTimeLocked();
     void flushAvailableGlobalRecordsToStatsLocked();
     bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName);
@@ -314,6 +355,9 @@
     GlobalRecord mGlobalRecord;
 
     static const size_t MAX_NUM_LAYER_RECORDS = 200;
+
+    static const size_t REFRESH_RATE_BUCKET_WIDTH = 30;
+    static const size_t RENDER_RATE_BUCKET_WIDTH = REFRESH_RATE_BUCKET_WIDTH;
     static const size_t MAX_NUM_LAYER_STATS = 200;
     static const size_t MAX_NUM_PULLED_LAYERS = MAX_NUM_LAYER_STATS;
     std::unique_ptr<StatsEventDelegate> mStatsDelegate = std::make_unique<StatsEventDelegate>();
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
index 9481cac..972edaa 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library {
     name: "libtimestats_proto",
     export_include_dirs: ["include"],
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 0fb748f..d116b02 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -41,7 +41,7 @@
     if (delta < 0) return;
     // std::lower_bound won't work on out of range values
     if (delta > histogramConfig[HISTOGRAM_SIZE - 1]) {
-        hist[histogramConfig[HISTOGRAM_SIZE - 1]] += delta / histogramConfig[HISTOGRAM_SIZE - 1];
+        hist[histogramConfig[HISTOGRAM_SIZE - 1]]++;
         return;
     }
     auto iter = std::lower_bound(histogramConfig.begin(), histogramConfig.end(), delta);
@@ -83,13 +83,18 @@
     StringAppendF(&result, "jankyFrames = %d\n", totalJankyFrames);
     StringAppendF(&result, "sfLongCpuJankyFrames = %d\n", totalSFLongCpu);
     StringAppendF(&result, "sfLongGpuJankyFrames = %d\n", totalSFLongGpu);
-    StringAppendF(&result, "sfUnattributedJankyFrame = %d\n", totalSFUnattributed);
-    StringAppendF(&result, "appUnattributedJankyFrame = %d\n", totalAppUnattributed);
+    StringAppendF(&result, "sfUnattributedJankyFrames = %d\n", totalSFUnattributed);
+    StringAppendF(&result, "appUnattributedJankyFrames = %d\n", totalAppUnattributed);
+    StringAppendF(&result, "sfSchedulingJankyFrames = %d\n", totalSFScheduling);
+    StringAppendF(&result, "sfPredictionErrorJankyFrames = %d\n", totalSFPredictionError);
+    StringAppendF(&result, "appBufferStuffingJankyFrames = %d\n", totalAppBufferStuffing);
     return result;
 }
 
 std::string TimeStatsHelper::TimeStatsLayer::toString() const {
     std::string result = "\n";
+    StringAppendF(&result, "displayRefreshRate = %d fps\n", displayRefreshRateBucket);
+    StringAppendF(&result, "renderRate = %d fps\n", renderRateBucket);
     StringAppendF(&result, "uid = %d\n", uid);
     StringAppendF(&result, "layerName = %s\n", layerName.c_str());
     StringAppendF(&result, "packageName = %s\n", packageName.c_str());
@@ -115,35 +120,49 @@
 
 std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> maxLayers) const {
     std::string result = "SurfaceFlinger TimeStats:\n";
-    StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStart);
-    StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEnd);
-    StringAppendF(&result, "totalFrames = %d\n", totalFrames);
-    StringAppendF(&result, "missedFrames = %d\n", missedFrames);
-    StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
-    StringAppendF(&result, "clientCompositionReusedFrames = %d\n", clientCompositionReusedFrames);
-    StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitches);
-    StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChanges);
-    StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
-    result.append("Global aggregated jank payload:\n");
-    result.append(jankPayload.toString());
+    result.append("Legacy stats are as follows:\n");
+    StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStartLegacy);
+    StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEndLegacy);
+    StringAppendF(&result, "totalFrames = %d\n", totalFramesLegacy);
+    StringAppendF(&result, "missedFrames = %d\n", missedFramesLegacy);
+    StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFramesLegacy);
+    StringAppendF(&result, "clientCompositionReusedFrames = %d\n",
+                  clientCompositionReusedFramesLegacy);
+    StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitchesLegacy);
+    StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChangesLegacy);
+    StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTimeLegacy);
     StringAppendF(&result, "displayConfigStats is as below:\n");
-    for (const auto& [fps, duration] : refreshRateStats) {
+    for (const auto& [fps, duration] : refreshRateStatsLegacy) {
         StringAppendF(&result, "%dfps = %ldms\n", fps, ns2ms(duration));
     }
     result.back() = '\n';
-    StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
+    StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresentLegacy.totalTime());
     StringAppendF(&result, "presentToPresent histogram is as below:\n");
-    result.append(presentToPresent.toString());
-    const float averageFrameDuration = frameDuration.averageTime();
+    result.append(presentToPresentLegacy.toString());
+    const float averageFrameDuration = frameDurationLegacy.averageTime();
     StringAppendF(&result, "averageFrameDuration = %.3f ms\n",
                   std::isnan(averageFrameDuration) ? 0.0f : averageFrameDuration);
     StringAppendF(&result, "frameDuration histogram is as below:\n");
-    result.append(frameDuration.toString());
-    const float averageRenderEngineTiming = renderEngineTiming.averageTime();
+    result.append(frameDurationLegacy.toString());
+    const float averageRenderEngineTiming = renderEngineTimingLegacy.averageTime();
     StringAppendF(&result, "averageRenderEngineTiming = %.3f ms\n",
                   std::isnan(averageRenderEngineTiming) ? 0.0f : averageRenderEngineTiming);
     StringAppendF(&result, "renderEngineTiming histogram is as below:\n");
-    result.append(renderEngineTiming.toString());
+    result.append(renderEngineTimingLegacy.toString());
+
+    result.append("\nGlobal aggregated jank payload (Timeline stats):");
+    for (const auto& ele : stats) {
+        result.append("\n");
+        StringAppendF(&result, "displayRefreshRate = %d fps\n",
+                      ele.second.key.displayRefreshRateBucket);
+        StringAppendF(&result, "renderRate = %d fps\n", ele.second.key.renderRateBucket);
+        result.append(ele.second.jankPayload.toString());
+        StringAppendF(&result, "sfDeadlineMisses histogram is as below:\n");
+        result.append(ele.second.displayDeadlineDeltas.toString());
+        StringAppendF(&result, "sfPredictionErrors histogram is as below:\n");
+        result.append(ele.second.displayPresentDeltas.toString());
+    }
+
     const auto dumpStats = generateDumpStats(maxLayers);
     for (const auto& ele : dumpStats) {
         result.append(ele->toString());
@@ -173,30 +192,30 @@
 SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto(
         std::optional<uint32_t> maxLayers) const {
     SFTimeStatsGlobalProto globalProto;
-    globalProto.set_stats_start(statsStart);
-    globalProto.set_stats_end(statsEnd);
-    globalProto.set_total_frames(totalFrames);
-    globalProto.set_missed_frames(missedFrames);
-    globalProto.set_client_composition_frames(clientCompositionFrames);
-    globalProto.set_display_on_time(displayOnTime);
-    for (const auto& ele : refreshRateStats) {
+    globalProto.set_stats_start(statsStartLegacy);
+    globalProto.set_stats_end(statsEndLegacy);
+    globalProto.set_total_frames(totalFramesLegacy);
+    globalProto.set_missed_frames(missedFramesLegacy);
+    globalProto.set_client_composition_frames(clientCompositionFramesLegacy);
+    globalProto.set_display_on_time(displayOnTimeLegacy);
+    for (const auto& ele : refreshRateStatsLegacy) {
         SFTimeStatsDisplayConfigBucketProto* configBucketProto =
                 globalProto.add_display_config_stats();
         SFTimeStatsDisplayConfigProto* configProto = configBucketProto->mutable_config();
         configProto->set_fps(ele.first);
         configBucketProto->set_duration_millis(ns2ms(ele.second));
     }
-    for (const auto& histEle : presentToPresent.hist) {
+    for (const auto& histEle : presentToPresentLegacy.hist) {
         SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present();
         histProto->set_time_millis(histEle.first);
         histProto->set_frame_count(histEle.second);
     }
-    for (const auto& histEle : frameDuration.hist) {
+    for (const auto& histEle : frameDurationLegacy.hist) {
         SFTimeStatsHistogramBucketProto* histProto = globalProto.add_frame_duration();
         histProto->set_time_millis(histEle.first);
         histProto->set_frame_count(histEle.second);
     }
-    for (const auto& histEle : renderEngineTiming.hist) {
+    for (const auto& histEle : renderEngineTimingLegacy.hist) {
         SFTimeStatsHistogramBucketProto* histProto = globalProto.add_render_engine_timing();
         histProto->set_time_millis(histEle.first);
         histProto->set_frame_count(histEle.second);
@@ -212,8 +231,18 @@
 std::vector<TimeStatsHelper::TimeStatsLayer const*>
 TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const {
     std::vector<TimeStatsLayer const*> dumpStats;
+
+    int numLayers = 0;
     for (const auto& ele : stats) {
-        dumpStats.push_back(&ele.second);
+        numLayers += ele.second.stats.size();
+    }
+
+    dumpStats.reserve(numLayers);
+
+    for (const auto& ele : stats) {
+        for (const auto& layerEle : ele.second.stats) {
+            dumpStats.push_back(&layerEle.second);
+        }
     }
 
     std::sort(dumpStats.begin(), dumpStats.end(),
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 033eb5d..4556bad 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -48,6 +48,9 @@
         int32_t totalSFLongGpu = 0;
         int32_t totalSFUnattributed = 0;
         int32_t totalAppUnattributed = 0;
+        int32_t totalSFScheduling = 0;
+        int32_t totalSFPredictionError = 0;
+        int32_t totalAppBufferStuffing = 0;
 
         std::string toString() const;
     };
@@ -57,6 +60,8 @@
         uid_t uid;
         std::string layerName;
         std::string packageName;
+        int32_t displayRefreshRateBucket = 0;
+        int32_t renderRateBucket = 0;
         int32_t totalFrames = 0;
         int32_t droppedFrames = 0;
         int32_t lateAcquireFrames = 0;
@@ -68,32 +73,84 @@
         SFTimeStatsLayerProto toProto() const;
     };
 
-    class TimeStatsGlobal {
-    public:
-        int64_t statsStart = 0;
-        int64_t statsEnd = 0;
-        int32_t totalFrames = 0;
-        int32_t missedFrames = 0;
-        int32_t clientCompositionFrames = 0;
-        int32_t clientCompositionReusedFrames = 0;
-        int32_t refreshRateSwitches = 0;
-        int32_t compositionStrategyChanges = 0;
-        int32_t displayEventConnectionsCount = 0;
-        int64_t displayOnTime = 0;
-        Histogram presentToPresent;
-        Histogram frameDuration;
-        Histogram renderEngineTiming;
+    // Lifted from SkiaGLRenderEngine's LinearEffect class.
+    // Which in turn was inspired by art/runtime/class_linker.cc
+    // Also this is what boost:hash_combine does so this is a pretty good hash.
+    static size_t HashCombine(size_t seed, size_t val) {
+        return seed ^ (val + 0x9e3779b9 + (seed << 6) + (seed >> 2));
+    }
 
-        struct StatsHasher {
-            size_t operator()(const std::pair<uid_t, std::string>& p) const {
-                // Normally this isn't a very good hash function due to symmetry reasons,
-                // but these are distinct types so this should be good enough
-                return std::hash<uid_t>{}(p.first) ^ std::hash<std::string>{}(p.second);
+    struct TimelineStatsKey {
+        int32_t displayRefreshRateBucket = 0;
+        int32_t renderRateBucket = 0;
+
+        struct Hasher {
+            size_t operator()(const TimelineStatsKey& key) const {
+                size_t result = std::hash<int32_t>{}(key.displayRefreshRateBucket);
+                return HashCombine(result, std::hash<int32_t>{}(key.renderRateBucket));
             }
         };
-        std::unordered_map<std::pair<uid_t, std::string>, TimeStatsLayer, StatsHasher> stats;
-        std::unordered_map<uint32_t, nsecs_t> refreshRateStats;
+
+        bool operator==(const TimelineStatsKey& o) const {
+            return displayRefreshRateBucket == o.displayRefreshRateBucket &&
+                    renderRateBucket == o.renderRateBucket;
+        }
+    };
+
+    struct LayerStatsKey {
+        uid_t uid = 0;
+        std::string layerName;
+
+        struct Hasher {
+            size_t operator()(const LayerStatsKey& key) const {
+                size_t result = std::hash<uid_t>{}(key.uid);
+                return HashCombine(result, std::hash<std::string>{}(key.layerName));
+            }
+        };
+
+        bool operator==(const LayerStatsKey& o) const {
+            return uid == o.uid && layerName == o.layerName;
+        }
+    };
+
+    struct LayerStatsHasher {
+        size_t operator()(const std::pair<uid_t, std::string>& p) const {
+            // Normally this isn't a very good hash function due to symmetry reasons,
+            // but these are distinct types so this should be good enough
+            return std::hash<uid_t>{}(p.first) ^ std::hash<std::string>{}(p.second);
+        }
+    };
+
+    struct TimelineStats {
+        TimelineStatsKey key;
         JankPayload jankPayload;
+        Histogram displayDeadlineDeltas;
+        Histogram displayPresentDeltas;
+        std::unordered_map<LayerStatsKey, TimeStatsLayer, LayerStatsKey::Hasher> stats;
+    };
+
+    class TimeStatsGlobal {
+    public:
+        // Note: these are all legacy statistics, we're keeping these around because a variety of
+        // systems and form-factors find these useful when comparing with older releases. However,
+        // the current recommendation is that the new timeline-based metrics are used, and the old
+        // ones are deprecated.
+        int64_t statsStartLegacy = 0;
+        int64_t statsEndLegacy = 0;
+        int32_t totalFramesLegacy = 0;
+        int32_t missedFramesLegacy = 0;
+        int32_t clientCompositionFramesLegacy = 0;
+        int32_t clientCompositionReusedFramesLegacy = 0;
+        int32_t refreshRateSwitchesLegacy = 0;
+        int32_t compositionStrategyChangesLegacy = 0;
+        int32_t displayEventConnectionsCountLegacy = 0;
+        int64_t displayOnTimeLegacy = 0;
+        Histogram presentToPresentLegacy;
+        Histogram frameDurationLegacy;
+        Histogram renderEngineTimingLegacy;
+        std::unordered_map<uint32_t, nsecs_t> refreshRateStatsLegacy;
+
+        std::unordered_map<TimelineStatsKey, TimelineStats, TimelineStatsKey::Hasher> stats;
 
         std::string toString(std::optional<uint32_t> maxLayers) const;
         SFTimeStatsGlobalProto toProto(std::optional<uint32_t> maxLayers) const;
diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp
index e2a28a2..c8a2b5e 100644
--- a/services/surfaceflinger/layerproto/Android.bp
+++ b/services/surfaceflinger/layerproto/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library {
     name: "liblayers_proto",
     export_include_dirs: ["include"],
diff --git a/services/surfaceflinger/sysprop/Android.bp b/services/surfaceflinger/sysprop/Android.bp
index 7721d7d2..f579119 100644
--- a/services/surfaceflinger/sysprop/Android.bp
+++ b/services/surfaceflinger/sysprop/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 sysprop_library {
     name: "SurfaceFlingerProperties",
     srcs: ["*.sysprop"],
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 8142aad..78187f7 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "SurfaceFlinger_test",
     defaults: ["surfaceflinger_defaults"],
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 9302463..6246321 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -25,7 +25,8 @@
 #include <gui/SurfaceComposerClient.h>
 #include <private/android_filesystem_config.h>
 #include <private/gui/ComposerService.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
+#include <ui/DynamicDisplayInfo.h>
 #include <utils/String8.h>
 #include <functional>
 #include "utils/ScreenshotUtils.h"
@@ -81,14 +82,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,23 +185,19 @@
     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));
-
-    ASSERT_TRUE(SurfaceComposerClient::getActiveConfig(display) >= 0);
-
-    ASSERT_NE(static_cast<ui::ColorMode>(BAD_VALUE),
-              SurfaceComposerClient::getActiveColorMode(display));
+    Vector<ui::DisplayMode> modes;
+    ui::DynamicDisplayInfo info;
+    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
 }
 
-TEST_F(CredentialsTest, GetDisplayColorModesTest) {
+TEST_F(CredentialsTest, GetDynamicDisplayInfoTest) {
     const auto display = SurfaceComposerClient::getInternalDisplayToken();
     std::function<status_t()> condition = [=]() {
-        Vector<ui::ColorMode> outColorModes;
-        return SurfaceComposerClient::getDisplayColorModes(display, &outColorModes);
+        ui::DynamicDisplayInfo info;
+        return SurfaceComposerClient::getDynamicDisplayInfo(display, &info);
     };
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
 }
@@ -217,25 +213,23 @@
 
 TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
     const auto display = SurfaceComposerClient::getInternalDisplayToken();
-    int32_t defaultConfig;
+    ui::DisplayModeId 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));
 }
@@ -358,8 +352,9 @@
     status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result);
     ASSERT_EQ(NO_ERROR, error);
     bool hasWideColorMode = false;
-    Vector<ColorMode> colorModes;
-    SurfaceComposerClient::getDisplayColorModes(display, &colorModes);
+    ui::DynamicDisplayInfo info;
+    SurfaceComposerClient::getDynamicDisplayInfo(display, &info);
+    const auto& colorModes = info.supportedColorModes;
     for (ColorMode colorMode : colorModes) {
         switch (colorMode) {
             case ColorMode::DISPLAY_P3:
@@ -387,7 +382,9 @@
 TEST_F(CredentialsTest, GetActiveColorModeBasicCorrectness) {
     const auto display = SurfaceComposerClient::getInternalDisplayToken();
     ASSERT_FALSE(display == nullptr);
-    ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(display);
+    ui::DynamicDisplayInfo info;
+    SurfaceComposerClient::getDynamicDisplayInfo(display, &info);
+    ColorMode colorMode = info.activeColorMode;
     ASSERT_NE(static_cast<ColorMode>(BAD_VALUE), colorMode);
 }
 
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 55b3173..2dc96b8 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -22,7 +22,8 @@
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
+#include <ui/DynamicDisplayInfo.h>
 #include <utils/Errors.h>
 #include <utils/Vector.h>
 
@@ -38,7 +39,7 @@
  */
 class RefreshRateRangeTest : public ::testing::Test {
 private:
-    int32_t initialDefaultConfig;
+    ui::DisplayModeId initialDefaultMode;
     bool initialAllowGroupSwitching;
     float initialPrimaryMin;
     float initialPrimaryMax;
@@ -49,25 +50,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 +77,60 @@
 };
 
 TEST_F(RefreshRateRangeTest, setAllConfigs) {
-    Vector<DisplayConfig> configs;
-    status_t res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
+    ui::DynamicDisplayInfo info;
+    status_t res = SurfaceComposerClient::getDynamicDisplayInfo(mDisplayToken, &info);
+    const auto& modes = info.supportedDisplayModes;
     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, modes[i].id, false,
+                                                                modes[i].refreshRate,
+                                                                modes[i].refreshRate,
+                                                                modes[i].refreshRate,
+                                                                modes[i].refreshRate);
         ASSERT_EQ(res, NO_ERROR);
 
-        int defaultConfig;
+        ui::DisplayModeId 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;
+    ui::DisplayModeId 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/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 3535fbb..2551a19 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "sffakehwc_test",
     defaults: ["surfaceflinger_defaults"],
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index efa15f1..11bd9eb 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -43,7 +43,8 @@
 #include <hwbinder/ProcessState.h>
 #include <log/log.h>
 #include <private/gui/ComposerService.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
+#include <ui/DynamicDisplayInfo.h>
 #include <utils/Looper.h>
 
 #include <gmock/gmock.h>
@@ -243,9 +244,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 +305,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 +313,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 +348,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 +380,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 +409,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 +433,12 @@
             }
         }
 
-        Vector<DisplayConfig> configs;
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
-        EXPECT_EQ(configs.size(), 2);
+        ui::DynamicDisplayInfo info;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
+        const auto& modes = info.supportedDisplayModes;
+        EXPECT_EQ(modes.size(), 2);
 
-        // change active config
+        // change active mode
 
         if (mIs2_4Client) {
             EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 2, _, _))
@@ -447,28 +448,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 +517,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 +541,12 @@
             }
         }
 
-        Vector<DisplayConfig> configs;
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
-        EXPECT_EQ(configs.size(), 2);
+        ui::DynamicDisplayInfo info;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
+        const auto& modes = info.supportedDisplayModes;
+        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 +555,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 +634,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 +658,12 @@
             }
         }
 
-        Vector<DisplayConfig> configs;
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
-        EXPECT_EQ(configs.size(), 4);
+        ui::DynamicDisplayInfo info;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
+        const auto& modes = info.supportedDisplayModes;
+        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 +672,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 +710,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 +719,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 +757,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 +766,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 +824,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 +850,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 +883,15 @@
 
         // 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);
+            ui::DynamicDisplayInfo info;
+            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
+            const auto& modes = info.supportedDisplayModes;
+            EXPECT_EQ(modes.size(), 1);
         }
 
         // Send another hotplug connected event
@@ -919,27 +922,28 @@
 
         // 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);
+        ui::DynamicDisplayInfo info;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info));
+        const auto& modes = info.supportedDisplayModes;
+        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 +956,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 +1172,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 17928a0..2ac6b09 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "libsurfaceflinger_unittest",
     defaults: ["surfaceflinger_defaults"],
@@ -73,6 +82,7 @@
         "FrameTracerTest.cpp",
         "TimerTest.cpp",
         "TransactionApplicationTest.cpp",
+        "TransactionFrameTracerTest.cpp",
         "TransactionSurfaceFrameTest.cpp",
         "StrongTypingTest.cpp",
         "VSyncDispatchTimerQueueTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index b696a6d..256be27 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -286,7 +286,7 @@
 
         auto ceDisplayArgs =
                 compositionengine::DisplayCreationArgsBuilder()
-                        .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+                        .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
                         .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
                         .setIsSecure(Derived::IS_SECURE)
                         .setLayerStackId(DEFAULT_LAYER_STACK)
@@ -300,7 +300,7 @@
                                                        ceDisplayArgs);
 
         test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay,
-                                                   DisplayConnectionType::Internal, HWC_DISPLAY,
+                                                   ui::DisplayConnectionType::Internal, HWC_DISPLAY,
                                                    true /* isPrimary */)
                                  .setDisplaySurface(test->mDisplaySurface)
                                  .setNativeWindow(test->mNativeWindow)
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 9069200..a3e8108 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -139,14 +139,14 @@
             createDisplay(mFlinger.getCompositionEngine(),
                           compositionengine::DisplayCreationArgsBuilder()
                                   .setPhysical(
-                                          {DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+                                          {DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
                                   .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
                                   .setPowerAdvisor(&mPowerAdvisor)
                                   .build());
 
-    auto injector =
-            FakeDisplayDeviceInjector(mFlinger, compositionDisplay, DisplayConnectionType::Internal,
-                                      DEFAULT_DISPLAY_HWC_DISPLAY_ID, true /* isPrimary */);
+    auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
+                                              ui::DisplayConnectionType::Internal,
+                                              DEFAULT_DISPLAY_HWC_DISPLAY_ID, true /* isPrimary */);
 
     injector.setNativeWindow(mNativeWindow);
     if (injectExtra) {
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 1664301..d68fff6 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -202,12 +202,13 @@
 
 template <typename>
 struct DisplayConnectionTypeGetter {
-    static constexpr std::optional<DisplayConnectionType> value;
+    static constexpr std::optional<ui::DisplayConnectionType> value;
 };
 
 template <typename PhysicalDisplay>
 struct DisplayConnectionTypeGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
-    static constexpr std::optional<DisplayConnectionType> value = PhysicalDisplay::CONNECTION_TYPE;
+    static constexpr std::optional<ui::DisplayConnectionType> value =
+            PhysicalDisplay::CONNECTION_TYPE;
 };
 
 template <typename>
@@ -263,7 +264,7 @@
     static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
         auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder();
         if (auto displayId = PhysicalDisplayId::tryCast(DISPLAY_ID::get())) {
-            ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal});
+            ceDisplayArgs.setPhysical({*displayId, ui::DisplayConnectionType::Internal});
         } else {
             // We turn off the use of HwcVirtualDisplays, to prevent Composition Engine
             // from calling into HWComposer. This way all virtual displays will get
@@ -457,7 +458,7 @@
 
     static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
         constexpr auto CONNECTION_TYPE =
-                PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
+                PhysicalDisplay::CONNECTION_TYPE == ui::DisplayConnectionType::Internal
                 ? IComposerClient::DisplayConnectionType::INTERNAL
                 : IComposerClient::DisplayConnectionType::EXTERNAL;
 
@@ -504,7 +505,7 @@
 
 template <bool hasIdentificationData>
 struct PrimaryDisplay {
-    static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal;
+    static constexpr auto CONNECTION_TYPE = ui::DisplayConnectionType::Internal;
     static constexpr Primary PRIMARY = Primary::TRUE;
     static constexpr uint8_t PORT = 255;
     static constexpr HWDisplayId HWC_DISPLAY_ID = 1001;
@@ -514,7 +515,7 @@
 
 template <bool hasIdentificationData>
 struct ExternalDisplay {
-    static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External;
+    static constexpr auto CONNECTION_TYPE = ui::DisplayConnectionType::External;
     static constexpr Primary PRIMARY = Primary::FALSE;
     static constexpr uint8_t PORT = 254;
     static constexpr HWDisplayId HWC_DISPLAY_ID = 1002;
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/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 6e9f09b..b8c1607 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -27,6 +27,7 @@
 #include <cinttypes>
 
 using namespace std::chrono_literals;
+using testing::_;
 using testing::AtLeast;
 using testing::Contains;
 using FrameTimelineEvent = perfetto::protos::FrameTimelineEvent;
@@ -40,10 +41,6 @@
 using ProtoPresentType = perfetto::protos::FrameTimelineEvent_PresentType;
 using ProtoJankType = perfetto::protos::FrameTimelineEvent_JankType;
 
-MATCHER_P(HasBit, bit, "") {
-    return (arg & bit) != 0;
-}
-
 namespace android::frametimeline {
 
 class FrameTimelineTest : public testing::Test {
@@ -109,6 +106,7 @@
 
     void addEmptyDisplayFrame() {
         auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+        // Trigger a flushPresentFence by calling setSfPresent for the next frame
         mFrameTimeline->setSfPresent(2500, presentFence1);
     }
 
@@ -158,12 +156,9 @@
     uint32_t* maxDisplayFrames;
     nsecs_t maxTokenRetentionTime;
     static constexpr pid_t kSurfaceFlingerPid = 666;
-    static constexpr nsecs_t kPresentThreshold =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count();
-    static constexpr nsecs_t kDeadlineThreshold =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count();
-    static constexpr nsecs_t kStartThreshold =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count();
+    static constexpr nsecs_t kPresentThreshold = std::chrono::nanoseconds(2ns).count();
+    static constexpr nsecs_t kDeadlineThreshold = std::chrono::nanoseconds(2ns).count();
+    static constexpr nsecs_t kStartThreshold = std::chrono::nanoseconds(2ns).count();
     static constexpr JankClassificationThresholds kTestThresholds{kPresentThreshold,
                                                                   kDeadlineThreshold,
                                                                   kStartThreshold};
@@ -237,50 +232,42 @@
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
-    int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
                                                        sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(token1, 20, 11);
+    mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11));
+    surfaceFrame1->setDropTime(12);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(25, presentFence1);
     presentFence1->signalForTest(30);
 
-    // Trigger a flush by calling setSfPresent for the next frame
-    mFrameTimeline->setSfWakeUp(token2, 50, 11);
-    mFrameTimeline->setSfPresent(55, presentFence2);
+    addEmptyDisplayFrame();
 
     auto& droppedSurfaceFrame = getSurfaceFrame(0, 0);
     EXPECT_EQ(droppedSurfaceFrame.getPresentState(), SurfaceFrame::PresentState::Dropped);
+    EXPECT_EQ(0u, droppedSurfaceFrame.getActuals().endTime);
+    EXPECT_EQ(12u, droppedSurfaceFrame.getDropTime());
     EXPECT_EQ(droppedSurfaceFrame.getActuals().presentTime, 0);
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
-    int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
-    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 60});
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     auto surfaceFrame2 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameTwo, sLayerNameTwo);
-    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -296,16 +283,7 @@
     EXPECT_EQ(presentedSurfaceFrame1.getActuals().presentTime, 0);
     EXPECT_EQ(presentedSurfaceFrame2.getActuals().presentTime, 0);
 
-    // Trigger a flush by finalizing the next DisplayFrame
-    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    auto surfaceFrame3 =
-            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
-                                                       sUidOne, sLayerNameOne, sLayerNameOne);
-    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
-    surfaceFrame3->setPresentState(SurfaceFrame::PresentState::Dropped);
-    mFrameTimeline->addSurfaceFrame(surfaceFrame3);
-    mFrameTimeline->setSfPresent(56, presentFence2);
-    displayFrame = getDisplayFrame(0);
+    addEmptyDisplayFrame();
 
     // Fences have flushed, so the present timestamps should be updated
     EXPECT_EQ(displayFrame->getActuals().presentTime, 42);
@@ -318,11 +296,8 @@
 TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) {
     // Insert kMaxDisplayFrames' count of DisplayFrames to fill the deque
     int frameTimeFactor = 0;
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
-            .Times(static_cast<int32_t>(*maxDisplayFrames));
     // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_))
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(_))
             .Times(static_cast<int32_t>(*maxDisplayFrames));
     for (size_t i = 0; i < *maxDisplayFrames; i++) {
         auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
@@ -334,7 +309,7 @@
                 mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId},
                                                            sPidOne, sUidOne, sLayerNameOne,
                                                            sLayerNameOne);
-        mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11);
+        mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11));
         surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
         mFrameTimeline->addSurfaceFrame(surfaceFrame);
         mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
@@ -355,7 +330,7 @@
     auto surfaceFrame =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
-    mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11);
+    mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11));
     surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame);
     mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
@@ -386,9 +361,6 @@
 }
 
 TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
-            .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
     auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     presentFence->signalForTest(2);
 
@@ -398,7 +370,7 @@
                 mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
                                                            sLayerNameOne);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
-        mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+        mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11));
         surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
         mFrameTimeline->addSurfaceFrame(surfaceFrame);
         mFrameTimeline->setSfPresent(27, presentFence);
@@ -408,16 +380,13 @@
     // Increase the size to 256
     mFrameTimeline->setMaxDisplayFrames(256);
     EXPECT_EQ(*maxDisplayFrames, 256u);
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
-            .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
 
     for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
         auto surfaceFrame =
                 mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
                                                            sLayerNameOne);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
-        mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+        mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11));
         surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
         mFrameTimeline->addSurfaceFrame(surfaceFrame);
         mFrameTimeline->setSfPresent(27, presentFence);
@@ -427,16 +396,13 @@
     // Shrink the size to 128
     mFrameTimeline->setMaxDisplayFrames(128);
     EXPECT_EQ(*maxDisplayFrames, 128u);
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_))
-            .Times(static_cast<int32_t>(*maxDisplayFrames + 10));
 
     for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
         auto surfaceFrame =
                 mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne,
                                                            sLayerNameOne);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
-        mFrameTimeline->setSfWakeUp(sfToken, 22, 11);
+        mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11));
         surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
         mFrameTimeline->addSurfaceFrame(surfaceFrame);
         mFrameTimeline->setSfPresent(27, presentFence);
@@ -446,93 +412,217 @@
 
 // Tests related to TimeStats
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
+    Fps refreshRate = Fps(11);
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(sUidOne, sLayerNameOne,
-                                     HasBit(JankType::SurfaceFlingerCpuDeadlineMissed)));
-    EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(HasBit(JankType::SurfaceFlingerCpuDeadlineMissed)));
+                incrementJankyFrames(
+                        TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+                                                   sLayerNameOne,
+                                                   JankType::SurfaceFlingerCpuDeadlineMissed,
+                                                   std::chrono::duration_cast<
+                                                           std::chrono::nanoseconds>(3ms)
+                                                           .count(),
+                                                   std::chrono::duration_cast<
+                                                           std::chrono::nanoseconds>(10ms)
+                                                           .count(),
+                                                   0}));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+            {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
+             std::chrono::nanoseconds(60ms).count()});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+            {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(),
+             std::chrono::nanoseconds(60ms).count()});
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
-    mFrameTimeline->setSfWakeUp(sfToken1,
-                                std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
-                                11);
+    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(20ms).count());
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
-    presentFence1->signalForTest(
-            std::chrono::duration_cast<std::chrono::nanoseconds>(70ms).count());
+    presentFence1->signalForTest(std::chrono::nanoseconds(70ms).count());
 
-    mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(),
-                                 presentFence1);
+    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(59ms).count(), presentFence1);
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
+    Fps refreshRate = Fps::fromPeriodNsecs(30);
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(sUidOne, sLayerNameOne, HasBit(JankType::DisplayHAL)));
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::DisplayHAL)));
+                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+                                                                sLayerNameOne, JankType::DisplayHAL,
+                                                                0, 0, 0}));
 
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+            {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
+             std::chrono::nanoseconds(60ms).count()});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+            {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(),
+             std::chrono::nanoseconds(60ms).count()});
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
-    mFrameTimeline->setSfWakeUp(sfToken1,
-                                std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
-                                30);
+    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(20ms).count());
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
-    presentFence1->signalForTest(
-            std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
-    mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
-                                 presentFence1);
+    presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
+    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1);
     EXPECT_EQ(surfaceFrame1->getJankType(), JankType::DisplayHAL);
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
+    Fps refreshRate = Fps(11.0);
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(sUidOne, sLayerNameOne,
-                                     HasBit(JankType::AppDeadlineMissed)));
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::AppDeadlineMissed)));
+                incrementJankyFrames(
+                        TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+                                                   sLayerNameOne, JankType::AppDeadlineMissed, 0, 0,
+                                                   std::chrono::duration_cast<
+                                                           std::chrono::nanoseconds>(25ms)
+                                                           .count()}));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()});
+            {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
+             std::chrono::nanoseconds(60ms).count()});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
-            {std::chrono::duration_cast<std::chrono::nanoseconds>(82ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(),
-             std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()});
+            {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(),
+             std::chrono::nanoseconds(90ms).count()});
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
-    surfaceFrame1->setAcquireFenceTime(
-            std::chrono::duration_cast<std::chrono::nanoseconds>(45ms).count());
-    mFrameTimeline->setSfWakeUp(sfToken1,
-                                std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(),
-                                11);
+    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(45ms).count());
+    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
 
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
-    presentFence1->signalForTest(
-            std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
-    mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(),
-                                 presentFence1);
+    presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
+    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1);
+
+    EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
+}
+
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) {
+    Fps refreshRate = Fps::fromPeriodNsecs(std::chrono::nanoseconds(32ms).count());
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(
+                        TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+                                                   sLayerNameOne,
+                                                   JankType::SurfaceFlingerScheduling, 0, 0,
+                                                   std::chrono::duration_cast<
+                                                           std::chrono::nanoseconds>(-10ms)
+                                                           .count()}));
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
+            {std::chrono::nanoseconds(40ms).count(), std::chrono::nanoseconds(60ms).count(),
+             std::chrono::nanoseconds(92ms).count()});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
+            {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(),
+             std::chrono::nanoseconds(60ms).count()});
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
+    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(50ms).count());
+    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    presentFence1->signalForTest(std::chrono::nanoseconds(60ms).count());
+    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1);
+
+    EXPECT_EQ(surfaceFrame1->getJankType(), JankType::SurfaceFlingerScheduling);
+}
+
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) {
+    Fps refreshRate = Fps(16.66f);
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(
+                        TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+                                                   sLayerNameOne, JankType::PredictionError, 0,
+                                                   std::chrono::duration_cast<
+                                                           std::chrono::nanoseconds>(5ms)
+                                                           .count(),
+                                                   0}));
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
+            {std::chrono::nanoseconds(30ms).count(), std::chrono::nanoseconds(40ms).count(),
+             std::chrono::nanoseconds(60ms).count()});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
+            {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(),
+             std::chrono::nanoseconds(60ms).count()});
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
+    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(40ms).count());
+    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    presentFence1->signalForTest(std::chrono::nanoseconds(65ms).count());
+    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1);
+
+    EXPECT_EQ(surfaceFrame1->getJankType(), JankType::PredictionError);
+}
+
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) {
+    Fps refreshRate = Fps::fromPeriodNsecs(std::chrono::nanoseconds(32ms).count());
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(
+                        TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+                                                   sLayerNameOne,
+                                                   JankType::BufferStuffing |
+                                                           JankType::SurfaceFlingerScheduling,
+                                                   0, 0, 0}));
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
+            {std::chrono::nanoseconds(30ms).count(), std::chrono::nanoseconds(40ms).count(),
+             std::chrono::nanoseconds(58ms).count()});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
+            {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(),
+             std::chrono::nanoseconds(90ms).count()});
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
+    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(40ms).count());
+    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(82ms).count(), refreshRate);
+
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented,
+                                   /*previousLatchTime*/
+                                   std::chrono::nanoseconds(56ms).count());
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
+    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1);
+
+    EXPECT_EQ(surfaceFrame1->getJankType(),
+              JankType::BufferStuffing | JankType::SurfaceFlingerScheduling);
+}
+
+TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) {
+    Fps refreshRate = Fps(11.0);
+    Fps renderRate = Fps(30.0);
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(
+                        TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne,
+                                                   JankType::AppDeadlineMissed, 0, 0,
+                                                   std::chrono::duration_cast<
+                                                           std::chrono::nanoseconds>(25ms)
+                                                           .count()}));
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
+            {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
+             std::chrono::nanoseconds(60ms).count()});
+    int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
+            {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(),
+             std::chrono::nanoseconds(90ms).count()});
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
+    surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(45ms).count());
+    mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    surfaceFrame1->setRenderRate(renderRate);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
+    mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1);
 
     EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
 }
@@ -547,28 +637,20 @@
  */
 TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) {
     auto tracingSession = getTracingSessionForTest();
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
-    int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
                                                        sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(token1, 20, 11);
+    mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(25, presentFence1);
     presentFence1->signalForTest(30);
 
-    // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
-    // next frame
-    mFrameTimeline->setSfWakeUp(token2, 50, 11);
-    mFrameTimeline->setSfPresent(55, presentFence2);
+    addEmptyDisplayFrame();
 
     auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
     EXPECT_EQ(packets.size(), 0u);
@@ -576,12 +658,9 @@
 
 TEST_F(FrameTimelineTest, tracing_sanityTest) {
     auto tracingSession = getTracingSessionForTest();
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
     tracingSession->StartBlocking();
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
@@ -591,18 +670,13 @@
                                                        sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(token2, 20, 11);
+    mFrameTimeline->setSfWakeUp(token2, 20, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(25, presentFence1);
     presentFence1->signalForTest(30);
 
-    // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
-    // next frame
-    mFrameTimeline->setSfWakeUp(token2, 50, 11);
-    mFrameTimeline->setSfPresent(55, presentFence2);
-    presentFence2->signalForTest(55);
-
+    addEmptyDisplayFrame();
     flushTrace();
     tracingSession->StopBlocking();
 
@@ -613,25 +687,16 @@
 
 TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) {
     auto tracingSession = getTracingSessionForTest();
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
     tracingSession->StartBlocking();
-    int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(-1, 20, 11);
+    mFrameTimeline->setSfWakeUp(-1, 20, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(25, presentFence1);
     presentFence1->signalForTest(30);
 
-    // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
-    // next frame
-    mFrameTimeline->setSfWakeUp(token1, 50, 11);
-    mFrameTimeline->setSfPresent(55, presentFence2);
-    presentFence2->signalForTest(60);
-
+    addEmptyDisplayFrame();
     flushTrace();
     tracingSession->StopBlocking();
 
@@ -641,30 +706,21 @@
 
 TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) {
     auto tracingSession = getTracingSessionForTest();
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
     tracingSession->StartBlocking();
     int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
-    int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
     auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne,
                                                                     sLayerNameOne, sLayerNameOne);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(token1, 20, 11);
+    mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(25, presentFence1);
     presentFence1->signalForTest(30);
 
-    // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
-    // next frame
-    mFrameTimeline->setSfWakeUp(token2, 50, 11);
-    mFrameTimeline->setSfPresent(55, presentFence2);
-    presentFence2->signalForTest(60);
-
+    addEmptyDisplayFrame();
     flushTrace();
     tracingSession->StopBlocking();
 
@@ -674,6 +730,65 @@
     EXPECT_EQ(packets.size(), 4u);
 }
 
+ProtoExpectedDisplayFrameStart createProtoExpectedDisplayFrameStart(int64_t cookie, int64_t token,
+                                                                    pid_t pid) {
+    ProtoExpectedDisplayFrameStart proto;
+    proto.set_cookie(cookie);
+    proto.set_token(token);
+    proto.set_pid(pid);
+    return proto;
+}
+
+ProtoActualDisplayFrameStart createProtoActualDisplayFrameStart(
+        int64_t cookie, int64_t token, pid_t pid, ProtoPresentType presentType, bool onTimeFinish,
+        bool gpuComposition, ProtoJankType jankType) {
+    ProtoActualDisplayFrameStart proto;
+    proto.set_cookie(cookie);
+    proto.set_token(token);
+    proto.set_pid(pid);
+    proto.set_present_type(presentType);
+    proto.set_on_time_finish(onTimeFinish);
+    proto.set_gpu_composition(gpuComposition);
+    proto.set_jank_type(jankType);
+    return proto;
+}
+
+ProtoExpectedSurfaceFrameStart createProtoExpectedSurfaceFrameStart(int64_t cookie, int64_t token,
+                                                                    int64_t displayFrameToken,
+                                                                    pid_t pid,
+                                                                    std::string layerName) {
+    ProtoExpectedSurfaceFrameStart proto;
+    proto.set_cookie(cookie);
+    proto.set_token(token);
+    proto.set_display_frame_token(displayFrameToken);
+    proto.set_pid(pid);
+    proto.set_layer_name(layerName);
+    return proto;
+}
+
+ProtoActualSurfaceFrameStart createProtoActualSurfaceFrameStart(
+        int64_t cookie, int64_t token, int64_t displayFrameToken, pid_t pid, std::string layerName,
+        ProtoPresentType presentType, bool onTimeFinish, bool gpuComposition,
+        ProtoJankType jankType) {
+    ProtoActualSurfaceFrameStart proto;
+    proto.set_cookie(cookie);
+    proto.set_token(token);
+    proto.set_display_frame_token(displayFrameToken);
+    proto.set_pid(pid);
+    proto.set_layer_name(layerName);
+    proto.set_present_type(presentType);
+    proto.set_on_time_finish(onTimeFinish);
+    proto.set_gpu_composition(gpuComposition);
+    proto.set_jank_type(jankType);
+    return proto;
+}
+
+ProtoFrameEnd createProtoFrameEnd(int64_t cookie) {
+    ProtoFrameEnd proto;
+    proto.set_cookie(cookie);
+    return proto;
+}
+
 void validateTraceEvent(const ProtoExpectedDisplayFrameStart& received,
                         const ProtoExpectedDisplayFrameStart& source) {
     ASSERT_TRUE(received.has_cookie());
@@ -759,48 +874,29 @@
 
 TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) {
     auto tracingSession = getTracingSessionForTest();
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
     tracingSession->StartBlocking();
     int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 25, 30});
-    int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, 11);
+    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(26, presentFence1);
     presentFence1->signalForTest(31);
 
     int64_t traceCookie = snoopCurrentTraceCookie();
-    ProtoExpectedDisplayFrameStart protoExpectedDisplayFrameStart;
-    protoExpectedDisplayFrameStart.set_cookie(traceCookie + 1);
-    protoExpectedDisplayFrameStart.set_token(displayFrameToken1);
-    protoExpectedDisplayFrameStart.set_pid(kSurfaceFlingerPid);
+    auto protoExpectedDisplayFrameStart =
+            createProtoExpectedDisplayFrameStart(traceCookie + 1, displayFrameToken1,
+                                                 kSurfaceFlingerPid);
+    auto protoExpectedDisplayFrameEnd = createProtoFrameEnd(traceCookie + 1);
+    auto protoActualDisplayFrameStart =
+            createProtoActualDisplayFrameStart(traceCookie + 2, displayFrameToken1,
+                                               kSurfaceFlingerPid,
+                                               FrameTimelineEvent::PRESENT_ON_TIME, true, false,
+                                               FrameTimelineEvent::JANK_NONE);
+    auto protoActualDisplayFrameEnd = createProtoFrameEnd(traceCookie + 2);
 
-    ProtoFrameEnd protoExpectedDisplayFrameEnd;
-    protoExpectedDisplayFrameEnd.set_cookie(traceCookie + 1);
-
-    ProtoActualDisplayFrameStart protoActualDisplayFrameStart;
-    protoActualDisplayFrameStart.set_cookie(traceCookie + 2);
-    protoActualDisplayFrameStart.set_token(displayFrameToken1);
-    protoActualDisplayFrameStart.set_pid(kSurfaceFlingerPid);
-    protoActualDisplayFrameStart.set_present_type(
-            ProtoPresentType(FrameTimelineEvent::PRESENT_ON_TIME));
-    protoActualDisplayFrameStart.set_on_time_finish(true);
-    protoActualDisplayFrameStart.set_gpu_composition(false);
-    protoActualDisplayFrameStart.set_jank_type(ProtoJankType(FrameTimelineEvent::JANK_NONE));
-
-    ProtoFrameEnd protoActualDisplayFrameEnd;
-    protoActualDisplayFrameEnd.set_cookie(traceCookie + 2);
-
-    // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
-    // next frame
-    mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, 11);
-    mFrameTimeline->setSfPresent(55, presentFence2);
-    presentFence2->signalForTest(55);
-
+    addEmptyDisplayFrame();
     flushTrace();
     tracingSession->StopBlocking();
 
@@ -852,75 +948,126 @@
     validateTraceEvent(actualDisplayFrameEnd, protoActualDisplayFrameEnd);
 }
 
+TEST_F(FrameTimelineTest, traceDisplayFrame_predictionExpiredDoesNotTraceExpectedTimeline) {
+    auto tracingSession = getTracingSessionForTest();
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+    tracingSession->StartBlocking();
+    int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 25, 30});
+    // Flush the token so that it would expire
+    flushTokens(systemTime() + maxTokenRetentionTime);
+
+    // Set up the display frame
+    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
+    mFrameTimeline->setSfPresent(26, presentFence1);
+    presentFence1->signalForTest(31);
+
+    int64_t traceCookie = snoopCurrentTraceCookie();
+
+    auto protoActualDisplayFrameStart =
+            createProtoActualDisplayFrameStart(traceCookie + 1, displayFrameToken1,
+                                               kSurfaceFlingerPid,
+                                               FrameTimelineEvent::PRESENT_UNSPECIFIED, false,
+                                               false, FrameTimelineEvent::JANK_UNKNOWN);
+    auto protoActualDisplayFrameEnd = createProtoFrameEnd(traceCookie + 1);
+
+    addEmptyDisplayFrame();
+    flushTrace();
+    tracingSession->StopBlocking();
+
+    auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
+    // Only actual timeline packets should be in the trace
+    EXPECT_EQ(packets.size(), 2u);
+
+    // Packet - 0 : ActualDisplayFrameStart
+    const auto& packet0 = packets[0];
+    ASSERT_TRUE(packet0.has_timestamp());
+    EXPECT_EQ(packet0.timestamp(), 20u);
+    ASSERT_TRUE(packet0.has_frame_timeline_event());
+
+    const auto& event0 = packet0.frame_timeline_event();
+    ASSERT_TRUE(event0.has_actual_display_frame_start());
+    const auto& actualDisplayFrameStart = event0.actual_display_frame_start();
+    validateTraceEvent(actualDisplayFrameStart, protoActualDisplayFrameStart);
+
+    // Packet - 1 : FrameEnd (ActualDisplayFrame)
+    const auto& packet1 = packets[1];
+    ASSERT_TRUE(packet1.has_timestamp());
+    EXPECT_EQ(packet1.timestamp(), 26u);
+    ASSERT_TRUE(packet1.has_frame_timeline_event());
+
+    const auto& event1 = packet1.frame_timeline_event();
+    ASSERT_TRUE(event1.has_frame_end());
+    const auto& actualDisplayFrameEnd = event1.frame_end();
+    validateTraceEvent(actualDisplayFrameEnd, protoActualDisplayFrameEnd);
+}
+
 TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) {
     auto tracingSession = getTracingSessionForTest();
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
     tracingSession->StartBlocking();
     int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 25, 40});
     int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({30, 35, 40});
-    int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
 
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
-    surfaceFrame1->setActualStartTime(0);
-    surfaceFrame1->setActualQueueTime(15);
-    surfaceFrame1->setAcquireFenceTime(20);
+    auto surfaceFrame2 =
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
+                                                       sUidOne, sLayerNameOne, sLayerNameOne);
+    surfaceFrame1->setActualQueueTime(10);
+    surfaceFrame1->setDropTime(15);
+
+    surfaceFrame2->setActualQueueTime(15);
+    surfaceFrame2->setAcquireFenceTime(20);
 
     // First 2 cookies will be used by the DisplayFrame
     int64_t traceCookie = snoopCurrentTraceCookie() + 2;
 
-    ProtoExpectedSurfaceFrameStart protoExpectedSurfaceFrameStart;
-    protoExpectedSurfaceFrameStart.set_cookie(traceCookie + 1);
-    protoExpectedSurfaceFrameStart.set_token(surfaceFrameToken);
-    protoExpectedSurfaceFrameStart.set_display_frame_token(displayFrameToken1);
-    protoExpectedSurfaceFrameStart.set_pid(sPidOne);
-    protoExpectedSurfaceFrameStart.set_layer_name(sLayerNameOne);
+    auto protoDroppedSurfaceFrameExpectedStart =
+            createProtoExpectedSurfaceFrameStart(traceCookie + 1, surfaceFrameToken,
+                                                 displayFrameToken1, sPidOne, sLayerNameOne);
+    auto protoDroppedSurfaceFrameExpectedEnd = createProtoFrameEnd(traceCookie + 1);
+    auto protoDroppedSurfaceFrameActualStart =
+            createProtoActualSurfaceFrameStart(traceCookie + 2, surfaceFrameToken,
+                                               displayFrameToken1, sPidOne, sLayerNameOne,
+                                               FrameTimelineEvent::PRESENT_DROPPED, false, false,
+                                               FrameTimelineEvent::JANK_NONE);
+    auto protoDroppedSurfaceFrameActualEnd = createProtoFrameEnd(traceCookie + 2);
 
-    ProtoFrameEnd protoExpectedSurfaceFrameEnd;
-    protoExpectedSurfaceFrameEnd.set_cookie(traceCookie + 1);
-
-    ProtoActualSurfaceFrameStart protoActualSurfaceFrameStart;
-    protoActualSurfaceFrameStart.set_cookie(traceCookie + 2);
-    protoActualSurfaceFrameStart.set_token(surfaceFrameToken);
-    protoActualSurfaceFrameStart.set_display_frame_token(displayFrameToken1);
-    protoActualSurfaceFrameStart.set_pid(sPidOne);
-    protoActualSurfaceFrameStart.set_layer_name(sLayerNameOne);
-    protoActualSurfaceFrameStart.set_present_type(
-            ProtoPresentType(FrameTimelineEvent::PRESENT_ON_TIME));
-    protoActualSurfaceFrameStart.set_on_time_finish(true);
-    protoActualSurfaceFrameStart.set_gpu_composition(false);
-    protoActualSurfaceFrameStart.set_jank_type(ProtoJankType(FrameTimelineEvent::JANK_NONE));
-
-    ProtoFrameEnd protoActualSurfaceFrameEnd;
-    protoActualSurfaceFrameEnd.set_cookie(traceCookie + 2);
+    auto protoPresentedSurfaceFrameExpectedStart =
+            createProtoExpectedSurfaceFrameStart(traceCookie + 3, surfaceFrameToken,
+                                                 displayFrameToken1, sPidOne, sLayerNameOne);
+    auto protoPresentedSurfaceFrameExpectedEnd = createProtoFrameEnd(traceCookie + 3);
+    auto protoPresentedSurfaceFrameActualStart =
+            createProtoActualSurfaceFrameStart(traceCookie + 4, surfaceFrameToken,
+                                               displayFrameToken1, sPidOne, sLayerNameOne,
+                                               FrameTimelineEvent::PRESENT_ON_TIME, true, false,
+                                               FrameTimelineEvent::JANK_NONE);
+    auto protoPresentedSurfaceFrameActualEnd = createProtoFrameEnd(traceCookie + 4);
 
     // Set up the display frame
-    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, 11);
-    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped);
+    surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame2);
     mFrameTimeline->setSfPresent(26, presentFence1);
     presentFence1->signalForTest(40);
 
-    // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the
-    // next frame
-    mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, 11);
-    mFrameTimeline->setSfPresent(55, presentFence2);
-    presentFence2->signalForTest(55);
-
+    addEmptyDisplayFrame();
     flushTrace();
     tracingSession->StopBlocking();
 
     auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
-    EXPECT_EQ(packets.size(), 8u);
+    // 4 DisplayFrame + 4 DroppedSurfaceFrame + 4 PresentedSurfaceFrame
+    EXPECT_EQ(packets.size(), 12u);
 
-    // Packet - 4 : ExpectedSurfaceFrameStart
+    // Packet - 4 : ExpectedSurfaceFrameStart1
     const auto& packet4 = packets[4];
     ASSERT_TRUE(packet4.has_timestamp());
     EXPECT_EQ(packet4.timestamp(), 10u);
@@ -928,10 +1075,10 @@
 
     const auto& event4 = packet4.frame_timeline_event();
     ASSERT_TRUE(event4.has_expected_surface_frame_start());
-    const auto& expectedSurfaceFrameStart = event4.expected_surface_frame_start();
-    validateTraceEvent(expectedSurfaceFrameStart, protoExpectedSurfaceFrameStart);
+    const auto& expectedSurfaceFrameStart1 = event4.expected_surface_frame_start();
+    validateTraceEvent(expectedSurfaceFrameStart1, protoDroppedSurfaceFrameExpectedStart);
 
-    // Packet - 5 : FrameEnd (ExpectedSurfaceFrame)
+    // Packet - 5 : FrameEnd (ExpectedSurfaceFrame1)
     const auto& packet5 = packets[5];
     ASSERT_TRUE(packet5.has_timestamp());
     EXPECT_EQ(packet5.timestamp(), 25u);
@@ -939,10 +1086,10 @@
 
     const auto& event5 = packet5.frame_timeline_event();
     ASSERT_TRUE(event5.has_frame_end());
-    const auto& expectedSurfaceFrameEnd = event5.frame_end();
-    validateTraceEvent(expectedSurfaceFrameEnd, protoExpectedSurfaceFrameEnd);
+    const auto& expectedSurfaceFrameEnd1 = event5.frame_end();
+    validateTraceEvent(expectedSurfaceFrameEnd1, protoDroppedSurfaceFrameExpectedEnd);
 
-    // Packet - 6 : ActualSurfaceFrameStart
+    // Packet - 6 : ActualSurfaceFrameStart1
     const auto& packet6 = packets[6];
     ASSERT_TRUE(packet6.has_timestamp());
     EXPECT_EQ(packet6.timestamp(), 10u);
@@ -950,34 +1097,157 @@
 
     const auto& event6 = packet6.frame_timeline_event();
     ASSERT_TRUE(event6.has_actual_surface_frame_start());
-    const auto& actualSurfaceFrameStart = event6.actual_surface_frame_start();
-    validateTraceEvent(actualSurfaceFrameStart, protoActualSurfaceFrameStart);
+    const auto& actualSurfaceFrameStart1 = event6.actual_surface_frame_start();
+    validateTraceEvent(actualSurfaceFrameStart1, protoDroppedSurfaceFrameActualStart);
 
-    // Packet - 7 : FrameEnd (ActualSurfaceFrame)
+    // Packet - 7 : FrameEnd (ActualSurfaceFrame1)
     const auto& packet7 = packets[7];
     ASSERT_TRUE(packet7.has_timestamp());
-    EXPECT_EQ(packet7.timestamp(), 20u);
+    EXPECT_EQ(packet7.timestamp(), 15u);
     ASSERT_TRUE(packet7.has_frame_timeline_event());
 
     const auto& event7 = packet7.frame_timeline_event();
     ASSERT_TRUE(event7.has_frame_end());
-    const auto& actualSurfaceFrameEnd = event7.frame_end();
+    const auto& actualSurfaceFrameEnd1 = event7.frame_end();
+    validateTraceEvent(actualSurfaceFrameEnd1, protoDroppedSurfaceFrameActualEnd);
+
+    // Packet - 8 : ExpectedSurfaceFrameStart2
+    const auto& packet8 = packets[8];
+    ASSERT_TRUE(packet8.has_timestamp());
+    EXPECT_EQ(packet8.timestamp(), 10u);
+    ASSERT_TRUE(packet8.has_frame_timeline_event());
+
+    const auto& event8 = packet8.frame_timeline_event();
+    ASSERT_TRUE(event8.has_expected_surface_frame_start());
+    const auto& expectedSurfaceFrameStart2 = event8.expected_surface_frame_start();
+    validateTraceEvent(expectedSurfaceFrameStart2, protoPresentedSurfaceFrameExpectedStart);
+
+    // Packet - 9 : FrameEnd (ExpectedSurfaceFrame2)
+    const auto& packet9 = packets[9];
+    ASSERT_TRUE(packet9.has_timestamp());
+    EXPECT_EQ(packet9.timestamp(), 25u);
+    ASSERT_TRUE(packet9.has_frame_timeline_event());
+
+    const auto& event9 = packet9.frame_timeline_event();
+    ASSERT_TRUE(event9.has_frame_end());
+    const auto& expectedSurfaceFrameEnd2 = event9.frame_end();
+    validateTraceEvent(expectedSurfaceFrameEnd2, protoPresentedSurfaceFrameExpectedEnd);
+
+    // Packet - 10 : ActualSurfaceFrameStart2
+    const auto& packet10 = packets[10];
+    ASSERT_TRUE(packet10.has_timestamp());
+    EXPECT_EQ(packet10.timestamp(), 10u);
+    ASSERT_TRUE(packet10.has_frame_timeline_event());
+
+    const auto& event10 = packet10.frame_timeline_event();
+    ASSERT_TRUE(event10.has_actual_surface_frame_start());
+    const auto& actualSurfaceFrameStart2 = event10.actual_surface_frame_start();
+    validateTraceEvent(actualSurfaceFrameStart2, protoPresentedSurfaceFrameActualStart);
+
+    // Packet - 11 : FrameEnd (ActualSurfaceFrame2)
+    const auto& packet11 = packets[11];
+    ASSERT_TRUE(packet11.has_timestamp());
+    EXPECT_EQ(packet11.timestamp(), 20u);
+    ASSERT_TRUE(packet11.has_frame_timeline_event());
+
+    const auto& event11 = packet11.frame_timeline_event();
+    ASSERT_TRUE(event11.has_frame_end());
+    const auto& actualSurfaceFrameEnd2 = event11.frame_end();
+    validateTraceEvent(actualSurfaceFrameEnd2, protoPresentedSurfaceFrameActualEnd);
+}
+
+TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpectedTimeline) {
+    auto tracingSession = getTracingSessionForTest();
+    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+    tracingSession->StartBlocking();
+    constexpr nsecs_t appStartTime =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count();
+    constexpr nsecs_t appEndTime =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count();
+    constexpr nsecs_t appPresentTime =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+    int64_t surfaceFrameToken =
+            mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime});
+
+    // Flush the token so that it would expire
+    flushTokens(systemTime() + maxTokenRetentionTime);
+    auto surfaceFrame1 =
+            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0},
+                                                       sPidOne, sUidOne, sLayerNameOne,
+                                                       sLayerNameOne);
+    surfaceFrame1->setActualQueueTime(appEndTime);
+    surfaceFrame1->setAcquireFenceTime(appEndTime);
+
+    constexpr nsecs_t sfStartTime =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count();
+    constexpr nsecs_t sfEndTime =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+    constexpr nsecs_t sfPresentTime =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+    int64_t displayFrameToken =
+            mTokenManager->generateTokenForPredictions({sfStartTime, sfEndTime, sfPresentTime});
+
+    // First 2 cookies will be used by the DisplayFrame
+    int64_t traceCookie = snoopCurrentTraceCookie() + 2;
+
+    auto protoActualSurfaceFrameStart =
+            createProtoActualSurfaceFrameStart(traceCookie + 1, surfaceFrameToken,
+                                               displayFrameToken, sPidOne, sLayerNameOne,
+                                               FrameTimelineEvent::PRESENT_UNSPECIFIED, false,
+                                               false, FrameTimelineEvent::JANK_UNKNOWN);
+    auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1);
+
+    // Set up the display frame
+    mFrameTimeline->setSfWakeUp(displayFrameToken, sfStartTime, Fps::fromPeriodNsecs(11));
+    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+    mFrameTimeline->setSfPresent(sfEndTime, presentFence1);
+    presentFence1->signalForTest(sfPresentTime);
+
+    addEmptyDisplayFrame();
+    flushTrace();
+    tracingSession->StopBlocking();
+
+    auto packets = readFrameTimelinePacketsBlocking(tracingSession.get());
+    // Display Frame 4 packets + SurfaceFrame 2 packets
+    ASSERT_EQ(packets.size(), 6u);
+
+    // Packet - 4 : ActualSurfaceFrameStart
+    const auto& packet4 = packets[4];
+    ASSERT_TRUE(packet4.has_timestamp());
+    EXPECT_EQ(packet4.timestamp(),
+              static_cast<uint64_t>(appEndTime - SurfaceFrame::kPredictionExpiredStartTimeDelta));
+    ASSERT_TRUE(packet4.has_frame_timeline_event());
+
+    const auto& event4 = packet4.frame_timeline_event();
+    ASSERT_TRUE(event4.has_actual_surface_frame_start());
+    const auto& actualSurfaceFrameStart = event4.actual_surface_frame_start();
+    validateTraceEvent(actualSurfaceFrameStart, protoActualSurfaceFrameStart);
+
+    // Packet - 5 : FrameEnd (ActualSurfaceFrame)
+    const auto& packet5 = packets[5];
+    ASSERT_TRUE(packet5.has_timestamp());
+    EXPECT_EQ(packet5.timestamp(), static_cast<uint64_t>(appEndTime));
+    ASSERT_TRUE(packet5.has_frame_timeline_event());
+
+    const auto& event5 = packet5.frame_timeline_event();
+    ASSERT_TRUE(event5.has_frame_end());
+    const auto& actualSurfaceFrameEnd = event5.frame_end();
     validateTraceEvent(actualSurfaceFrameEnd, protoActualSurfaceFrameEnd);
 }
 
 // Tests for Jank classification
 TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
     auto surfaceFrame =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
-    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame);
     mFrameTimeline->setSfPresent(26, presentFence1);
@@ -1001,12 +1271,11 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
+    Fps vsyncRate = Fps::fromPeriodNsecs(11);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
-    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate);
     mFrameTimeline->setSfPresent(26, presentFence1);
     auto displayFrame = getDisplayFrame(0);
     presentFence1->signalForTest(30);
@@ -1016,7 +1285,7 @@
 
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, vsyncRate);
     mFrameTimeline->setSfPresent(56, presentFence2);
     displayFrame = getDisplayFrame(0);
 
@@ -1030,7 +1299,6 @@
     auto displayFrame2 = getDisplayFrame(1);
     presentFence2->signalForTest(65);
     EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
-
     addEmptyDisplayFrame();
     displayFrame2 = getDisplayFrame(1);
 
@@ -1042,12 +1310,11 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
+    Fps vsyncRate = Fps::fromPeriodNsecs(11);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
-    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate);
     mFrameTimeline->setSfPresent(26, presentFence1);
     auto displayFrame = getDisplayFrame(0);
     presentFence1->signalForTest(50);
@@ -1057,7 +1324,7 @@
 
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
-    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, vsyncRate);
     mFrameTimeline->setSfPresent(56, presentFence2);
     displayFrame = getDisplayFrame(0);
 
@@ -1083,11 +1350,9 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({12, 18, 40});
-    mFrameTimeline->setSfWakeUp(sfToken1, 12, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
 
     mFrameTimeline->setSfPresent(22, presentFence1);
     auto displayFrame = getDisplayFrame(0);
@@ -1107,11 +1372,9 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
-    mFrameTimeline->setSfWakeUp(sfToken1, 12, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
     mFrameTimeline->setSfPresent(36, presentFence1);
     auto displayFrame = getDisplayFrame(0);
     presentFence1->signalForTest(52);
@@ -1130,10 +1393,7 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
-    // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
@@ -1143,7 +1403,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(16);
-    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(26, presentFence1);
@@ -1162,7 +1422,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame2->setAcquireFenceTime(36);
-    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame2);
     mFrameTimeline->setSfPresent(56, presentFence2);
@@ -1187,6 +1447,14 @@
     auto actuals2 = presentedSurfaceFrame2.getActuals();
     EXPECT_EQ(actuals2.presentTime, 0);
 
+    ::testing::Mock::VerifyAndClearExpectations(mTimeStats.get());
+
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(
+                        TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne,
+                                                   sLayerNameOne, JankType::PredictionError, 0, 5,
+                                                   0}));
+
     addEmptyDisplayFrame();
 
     // Fences for the second frame have flushed, so the present timestamps should be updated
@@ -1203,10 +1471,7 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
-    // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
@@ -1216,7 +1481,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(16);
-    mFrameTimeline->setSfWakeUp(sfToken1, 22, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(26, presentFence1);
@@ -1235,7 +1500,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame2->setAcquireFenceTime(36);
-    mFrameTimeline->setSfWakeUp(sfToken2, 52, 11);
+    mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame2);
     mFrameTimeline->setSfPresent(56, presentFence2);
@@ -1260,6 +1525,14 @@
     auto actuals2 = presentedSurfaceFrame2.getActuals();
     EXPECT_EQ(actuals2.presentTime, 0);
 
+    ::testing::Mock::VerifyAndClearExpectations(mTimeStats.get());
+
+    EXPECT_CALL(*mTimeStats,
+                incrementJankyFrames(
+                        TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne,
+                                                   sLayerNameOne, JankType::PredictionError, 0, 5,
+                                                   0}));
+
     addEmptyDisplayFrame();
 
     // Fences for the second frame have flushed, so the present timestamps should be updated
@@ -1276,10 +1549,8 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_));
-    // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_));
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
+
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 46, 50});
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60});
@@ -1287,7 +1558,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(40);
-    mFrameTimeline->setSfWakeUp(sfToken1, 42, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 42, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(46, presentFence1);
@@ -1320,10 +1591,7 @@
     // AppDeadlineMissed. Second frame - DisplayFrame is janky. This should propagate DisplayFrame's
     // jank to the SurfaceFrame.
 
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
-    // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({32, 36, 40});
     int64_t sfToken2 = mTokenManager->generateTokenForPredictions({42, 46, 50});
@@ -1333,7 +1601,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(26);
-    mFrameTimeline->setSfWakeUp(sfToken1, 32, 11);
+    mFrameTimeline->setSfWakeUp(sfToken1, 32, Fps::fromPeriodNsecs(11));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(36, presentFence1);
@@ -1352,7 +1620,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame2->setAcquireFenceTime(40);
-    mFrameTimeline->setSfWakeUp(sfToken2, 43, 11);
+    mFrameTimeline->setSfWakeUp(sfToken2, 43, Fps::fromPeriodNsecs(11));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame2);
     mFrameTimeline->setSfPresent(56, presentFence2);
@@ -1393,10 +1661,8 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadlineMissed) {
-    // Global increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2);
     // Layer specific increment
-    EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2);
+    EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
@@ -1407,7 +1673,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame1->setAcquireFenceTime(50);
-    mFrameTimeline->setSfWakeUp(sfToken1, 52, 30);
+    mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30));
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
     mFrameTimeline->addSurfaceFrame(surfaceFrame1);
     mFrameTimeline->setSfPresent(56, presentFence1);
@@ -1426,7 +1692,7 @@
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
                                                        sUidOne, sLayerNameOne, sLayerNameOne);
     surfaceFrame2->setAcquireFenceTime(84);
-    mFrameTimeline->setSfWakeUp(sfToken2, 112, 30);
+    mFrameTimeline->setSfWakeUp(sfToken2, 112, Fps::fromPeriodNsecs(30));
     surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54);
     mFrameTimeline->addSurfaceFrame(surfaceFrame2);
     mFrameTimeline->setSfPresent(116, presentFence2);
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..06f2036 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)));
 }
@@ -1791,6 +1792,26 @@
     ASSERT_TRUE(frameRateOverrides.empty());
 }
 
+TEST_F(RefreshRateConfigsTest, updateDisplayModes) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_30);
+    refreshRateConfigs->setDisplayManagerPolicy({DisplayModeId(HWC_CONFIG_ID_30),
+                                                 /* allowGroupSwitching */ false,
+                                                 /* range */ {Fps(30.0f), Fps(30.0f)}});
+
+    refreshRateConfigs->updateDisplayModes(m60_90Device, HWC_CONFIG_ID_60);
+
+    const auto currentRefreshRate = refreshRateConfigs->getCurrentRefreshRate();
+    EXPECT_TRUE(currentRefreshRate.getFps().equalsWithMargin(Fps(60.0)));
+    EXPECT_EQ(currentRefreshRate.getModeId(), HWC_CONFIG_ID_60);
+
+    EXPECT_TRUE(
+            getMaxSupportedRefreshRate(*refreshRateConfigs).getFps().equalsWithMargin(Fps(90.0)));
+    EXPECT_TRUE(
+            getMinSupportedRefreshRate(*refreshRateConfigs).getFps().equalsWithMargin(Fps(60.0)));
+}
+
 } // namespace
 } // namespace scheduler
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index ceccd81..bf07106 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -53,7 +53,7 @@
         mRefreshRateConfigs =
                 std::make_unique<RefreshRateConfigs>(configs, /*currentConfig=*/CONFIG_ID_0);
 
-        const auto currFps = mRefreshRateConfigs->getRefreshRateFromConfigId(CONFIG_ID_0).getFps();
+        const auto currFps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
         mRefreshRateStats = std::make_unique<RefreshRateStats>(mTimeStats, currFps,
                                                                /*currentPowerMode=*/PowerMode::OFF);
     }
@@ -62,7 +62,7 @@
     std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
     std::unique_ptr<RefreshRateStats> mRefreshRateStats;
 
-    DisplayModePtr createConfig(DisplayModeId configId, int32_t configGroup, int64_t vsyncPeriod);
+    DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod);
 };
 
 RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -77,12 +77,12 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-DisplayModePtr RefreshRateStatsTest::createConfig(DisplayModeId configId, int32_t configGroup,
-                                                  int64_t vsyncPeriod) {
-    return DisplayMode::Builder(static_cast<hal::HWConfigId>(configId.value()))
-            .setId(configId)
+DisplayModePtr RefreshRateStatsTest::createDisplayMode(DisplayModeId modeId, int32_t group,
+                                                       int64_t vsyncPeriod) {
+    return DisplayMode::Builder(static_cast<hal::HWConfigId>(modeId.value()))
+            .setId(modeId)
             .setVsyncPeriod(static_cast<int32_t>(vsyncPeriod))
-            .setConfigGroup(configGroup)
+            .setGroup(group)
             .build();
 }
 
@@ -91,7 +91,7 @@
  * Test cases
  */
 TEST_F(RefreshRateStatsTest, oneConfigTest) {
-    init({createConfig(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90)});
+    init({createDisplayMode(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90)});
 
     EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
     EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
@@ -110,7 +110,7 @@
     EXPECT_LT(screenOff, times["ScreenOff"]);
     EXPECT_EQ(0u, times.count("90.00fps"));
 
-    const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromConfigId(CONFIG_ID_0).getFps();
+    const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
     mRefreshRateStats->setRefreshRate(config0Fps);
     mRefreshRateStats->setPowerMode(PowerMode::ON);
     screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
@@ -138,8 +138,8 @@
 }
 
 TEST_F(RefreshRateStatsTest, twoConfigsTest) {
-    init({createConfig(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90),
-          createConfig(CONFIG_ID_1, CONFIG_GROUP_0, VSYNC_60)});
+    init({createDisplayMode(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90),
+          createDisplayMode(CONFIG_ID_1, CONFIG_GROUP_0, VSYNC_60)});
 
     EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
     EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
@@ -158,8 +158,8 @@
     times = mRefreshRateStats->getTotalTimes();
     EXPECT_LT(screenOff, times["ScreenOff"]);
 
-    const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromConfigId(CONFIG_ID_0).getFps();
-    const auto config1Fps = mRefreshRateConfigs->getRefreshRateFromConfigId(CONFIG_ID_1).getFps();
+    const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
+    const auto config1Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_1).getFps();
     mRefreshRateStats->setRefreshRate(config0Fps);
     mRefreshRateStats->setPowerMode(PowerMode::ON);
     screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index e688e10..e46a270 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -52,7 +52,7 @@
     SchedulerTest();
 
     const scheduler::RefreshRateConfigs
-            mConfigs{{DisplayMode::Builder(0).setVsyncPeriod(16'666'667).setConfigGroup(0).build()},
+            mConfigs{{DisplayMode::Builder(0).setVsyncPeriod(16'666'667).setGroup(0).build()},
                      DisplayModeId(0)};
 
     mock::SchedulerCallback mSchedulerCallback;
@@ -69,6 +69,8 @@
     Scheduler::ConnectionHandle mConnectionHandle;
     mock::EventThread* mEventThread;
     sp<MockEventThreadConnection> mEventThreadConnection;
+
+    TestableSurfaceFlinger mFlinger;
 };
 
 SchedulerTest::SchedulerTest() {
@@ -166,25 +168,35 @@
     mScheduler.chooseRefreshRateForContent();
 }
 
-TEST_F(SchedulerTest, testDispatchCachedReportedConfig) {
+TEST_F(SchedulerTest, testDispatchCachedReportedMode) {
     // If the optional fields are cleared, the function should return before
-    // onConfigChange is called.
+    // onModeChange is called.
     mScheduler.clearOptionalFieldsInFeatures();
-    EXPECT_NO_FATAL_FAILURE(mScheduler.dispatchCachedReportedConfig());
-    EXPECT_CALL(*mEventThread, onConfigChanged(_, _, _)).Times(0);
+    EXPECT_NO_FATAL_FAILURE(mScheduler.dispatchCachedReportedMode());
+    EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0);
 }
 
-TEST_F(SchedulerTest, onNonPrimaryDisplayConfigChanged_invalidParameters) {
-    DisplayModeId configId = DisplayModeId(111);
+TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) {
+    DisplayModeId modeId = DisplayModeId(111);
     nsecs_t vsyncPeriod = 111111;
 
     // If the handle is incorrect, the function should return before
-    // onConfigChange is called.
+    // onModeChange is called.
     Scheduler::ConnectionHandle invalidHandle = {.id = 123};
-    EXPECT_NO_FATAL_FAILURE(mScheduler.onNonPrimaryDisplayConfigChanged(invalidHandle,
-                                                                        PHYSICAL_DISPLAY_ID,
-                                                                        configId, vsyncPeriod));
-    EXPECT_CALL(*mEventThread, onConfigChanged(_, _, _)).Times(0);
+    EXPECT_NO_FATAL_FAILURE(mScheduler.onNonPrimaryDisplayModeChanged(invalidHandle,
+                                                                      PHYSICAL_DISPLAY_ID, modeId,
+                                                                      vsyncPeriod));
+    EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0);
+}
+
+TEST_F(SchedulerTest, calculateExtraBufferCount) {
+    EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 30ms));
+    EXPECT_EQ(1, mFlinger.calculateExtraBufferCount(Fps(90), 30ms));
+    EXPECT_EQ(2, mFlinger.calculateExtraBufferCount(Fps(120), 30ms));
+
+    EXPECT_EQ(1, mFlinger.calculateExtraBufferCount(Fps(60), 40ms));
+
+    EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 10ms));
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/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 3787c43..2ba6490 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);
@@ -391,6 +391,11 @@
 
     auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); }
 
+    auto calculateExtraBufferCount(Fps maxSupportedRefreshRate,
+                                   std::chrono::nanoseconds presentLatency) const {
+        return SurfaceFlinger::calculateExtraBufferCount(maxSupportedRefreshRate, presentLatency);
+    }
+
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
@@ -405,6 +410,10 @@
 
     const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; }
 
+    mock::FrameTracer* getFrameTracer() const {
+        return static_cast<mock::FrameTracer*>(mFlinger->mFrameTracer.get());
+    }
+
     /* ------------------------------------------------------------------------
      * Read-write access to private data to set up preconditions and assert
      * post-conditions.
@@ -625,7 +634,7 @@
     public:
         FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
                                   std::shared_ptr<compositionengine::Display> compositionDisplay,
-                                  std::optional<DisplayConnectionType> connectionType,
+                                  std::optional<ui::DisplayConnectionType> connectionType,
                                   std::optional<hal::HWDisplayId> hwcDisplayId, bool isPrimary)
               : mFlinger(flinger),
                 mCreationArgs(flinger.mFlinger.get(), flinger.mFlinger->getHwComposer(),
@@ -643,7 +652,7 @@
                             .setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)
                             .setDpiX(FakeHwcDisplayInjector::DEFAULT_DPI)
                             .setDpiY(FakeHwcDisplayInjector::DEFAULT_DPI)
-                            .setConfigGroup(0)
+                            .setGroup(0)
                             .build();
 
             DisplayModes modes{activeMode};
@@ -756,7 +765,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/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index df4464e..e903664 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -55,14 +55,21 @@
 using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode;
 
 // clang-format off
-#define FMT_PROTO          true
-#define FMT_STRING         false
-#define LAYER_ID_0         0
-#define LAYER_ID_1         1
-#define UID_0              123
-#define LAYER_ID_INVALID   -1
-#define NUM_LAYERS         1
-#define NUM_LAYERS_INVALID "INVALID"
+#define FMT_PROTO             true
+#define FMT_STRING            false
+#define LAYER_ID_0            0
+#define LAYER_ID_1            1
+#define UID_0                 123
+#define REFRESH_RATE_0        61
+#define RENDER_RATE_0         31
+#define REFRESH_RATE_BUCKET_0 60
+#define RENDER_RATE_BUCKET_0  30
+#define LAYER_ID_INVALID      -1
+#define NUM_LAYERS            1
+#define NUM_LAYERS_INVALID    "INVALID"
+
+const constexpr Fps kRefreshRate0 = Fps(static_cast<float>(REFRESH_RATE_0));
+const constexpr Fps kRenderRate0 = Fps(static_cast<float>(RENDER_RATE_0));
 
 enum InputCommand : int32_t {
     ENABLE                 = 0,
@@ -246,11 +253,13 @@
             ASSERT_NO_FATAL_FAILURE(mTimeStats->setDesiredTime(id, frameNumber, ts));
             break;
         case TimeStamp::PRESENT:
-            ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentTime(id, frameNumber, ts));
+            ASSERT_NO_FATAL_FAILURE(
+                    mTimeStats->setPresentTime(id, frameNumber, ts, kRefreshRate0, kRenderRate0));
             break;
         case TimeStamp::PRESENT_FENCE:
-            ASSERT_NO_FATAL_FAILURE(
-                    mTimeStats->setPresentFence(id, frameNumber, std::make_shared<FenceTime>(ts)));
+            ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentFence(id, frameNumber,
+                                                                std::make_shared<FenceTime>(ts),
+                                                                kRefreshRate0, kRenderRate0));
             break;
         default:
             ALOGD("Invalid timestamp type");
@@ -352,58 +361,52 @@
     EXPECT_THAT(result, HasSubstr(expectedResult));
 }
 
-TEST_F(TimeStatsTest, canIncreaseJankyFrames) {
-    // this stat is not in the proto so verify by checking the string dump
-    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
-
-    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
-    mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerCpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::DisplayHAL);
-    mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::None);
-
-    const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
-    std::string expectedResult = "totalTimelineFrames = " + std::to_string(5);
-    EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "jankyFrames = " + std::to_string(4);
-    EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
-    EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
-    EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "sfUnattributedJankyFrame = " + std::to_string(1);
-    EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "appUnattributedJankyFrame = " + std::to_string(1);
-    EXPECT_THAT(result, HasSubstr(expectedResult));
-}
-
 TEST_F(TimeStatsTest, canIncreaseJankyFramesForLayer) {
     // this stat is not in the proto so verify by checking the string dump
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
 
     insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
-                                     JankType::SurfaceFlingerCpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
-                                     JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
-                                     JankType::AppDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::DisplayHAL, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::AppDeadlineMissed, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::SurfaceFlingerScheduling, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::PredictionError, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2,
+                                      3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::None, 1, 2, 3});
 
     const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
-    std::string expectedResult = "totalTimelineFrames = " + std::to_string(5);
+    std::string expectedResult =
+            "displayRefreshRate = " + std::to_string(REFRESH_RATE_BUCKET_0) + " fps";
     EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "jankyFrames = " + std::to_string(4);
+    expectedResult = "renderRate = " + std::to_string(RENDER_RATE_BUCKET_0) + " fps";
+    EXPECT_THAT(result, HasSubstr(expectedResult));
+    expectedResult = "totalTimelineFrames = " + std::to_string(8);
+    EXPECT_THAT(result, HasSubstr(expectedResult));
+    expectedResult = "jankyFrames = " + std::to_string(7);
     EXPECT_THAT(result, HasSubstr(expectedResult));
     expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
     EXPECT_THAT(result, HasSubstr(expectedResult));
     expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
     EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "sfUnattributedJankyFrame = " + std::to_string(1);
+    expectedResult = "sfUnattributedJankyFrames = " + std::to_string(1);
     EXPECT_THAT(result, HasSubstr(expectedResult));
-    expectedResult = "appUnattributedJankyFrame = " + std::to_string(1);
+    expectedResult = "appUnattributedJankyFrames = " + std::to_string(2);
+    EXPECT_THAT(result, HasSubstr(expectedResult));
+    expectedResult = "sfSchedulingJankyFrames = " + std::to_string(1);
+    EXPECT_THAT(result, HasSubstr(expectedResult));
+    expectedResult = "sfPredictionErrorJankyFrames = " + std::to_string(1);
+    EXPECT_THAT(result, HasSubstr(expectedResult));
+    expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(1);
     EXPECT_THAT(result, HasSubstr(expectedResult));
 }
 
@@ -455,14 +458,10 @@
 TEST_F(TimeStatsTest, canAverageFrameDuration) {
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
     mTimeStats->setPowerMode(PowerMode::ON);
-    mTimeStats
-            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
-                                  std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
-                                          .count());
-    mTimeStats
-            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
-                                  std::chrono::duration_cast<std::chrono::nanoseconds>(16ms)
-                                          .count());
+    mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
+                                    std::chrono::nanoseconds(6ms).count());
+    mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
+                                    std::chrono::nanoseconds(16ms).count());
 
     const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
     EXPECT_THAT(result, HasSubstr("averageFrameDuration = 10.000 ms"));
@@ -470,22 +469,19 @@
 
 TEST_F(TimeStatsTest, canAverageRenderEngineTimings) {
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
-    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
-                                                   .count(),
+    mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(1ms).count(),
                                            std::make_shared<FenceTime>(
                                                    std::chrono::duration_cast<
                                                            std::chrono::nanoseconds>(3ms)
                                                            .count()));
 
-    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
-                                                   .count(),
-                                           std::chrono::duration_cast<std::chrono::nanoseconds>(8ms)
-                                                   .count());
+    mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(4ms).count(),
+                                           std::chrono::nanoseconds(8ms).count());
 
     // Push a fake present fence to trigger flushing the RenderEngine timings.
     mTimeStats->setPowerMode(PowerMode::ON);
-    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
-            std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+    mTimeStats->setPresentFenceGlobal(
+            std::make_shared<FenceTime>(std::chrono::nanoseconds(1ms).count()));
 
     const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
     EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 3.000 ms"));
@@ -524,15 +520,11 @@
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
 
     mTimeStats->setPowerMode(PowerMode::OFF);
-    mTimeStats
-            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
-                                  std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
-                                          .count());
+    mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
+                                    std::chrono::nanoseconds(5ms).count());
     mTimeStats->setPowerMode(PowerMode::ON);
-    mTimeStats
-            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
-                                  std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
-                                          .count());
+    mTimeStats->recordFrameDuration(std::chrono::nanoseconds(3ms).count(),
+                                    std::chrono::nanoseconds(6ms).count());
 
     SFTimeStatsGlobalProto globalProto;
     ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
@@ -546,17 +538,14 @@
 TEST_F(TimeStatsTest, canInsertGlobalRenderEngineTiming) {
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
 
-    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
-                                                   .count(),
+    mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(1ms).count(),
                                            std::make_shared<FenceTime>(
                                                    std::chrono::duration_cast<
                                                            std::chrono::nanoseconds>(3ms)
                                                            .count()));
 
-    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
-                                                   .count(),
-                                           std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
-                                                   .count());
+    mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(4ms).count(),
+                                           std::chrono::nanoseconds(6ms).count());
 
     // First verify that flushing RenderEngine durations did not occur yet.
     SFTimeStatsGlobalProto preFlushProto;
@@ -565,8 +554,8 @@
 
     // Push a fake present fence to trigger flushing the RenderEngine timings.
     mTimeStats->setPowerMode(PowerMode::ON);
-    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
-            std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+    mTimeStats->setPresentFenceGlobal(
+            std::make_shared<FenceTime>(std::chrono::nanoseconds(1ms).count()));
 
     // Now we can verify that RenderEngine durations were flushed now.
     SFTimeStatsGlobalProto postFlushProto;
@@ -801,14 +790,10 @@
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
     ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
 
-    mTimeStats
-            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
-                                  std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
-                                          .count());
-    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
-                                                   .count(),
-                                           std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
-                                                   .count());
+    mTimeStats->recordFrameDuration(std::chrono::nanoseconds(3ms).count(),
+                                    std::chrono::nanoseconds(6ms).count());
+    mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(4ms).count(),
+                                           std::chrono::nanoseconds(6ms).count());
     ASSERT_NO_FATAL_FAILURE(
             mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
     ASSERT_NO_FATAL_FAILURE(
@@ -837,25 +822,30 @@
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
     mTimeStats->setPowerMode(PowerMode::ON);
-    mTimeStats
-            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
-                                  std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
-                                          .count());
-    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
-                                                   .count(),
-                                           std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
-                                                   .count());
-    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
-            std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+    mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(),
+                                    std::chrono::nanoseconds(5ms).count());
+    mTimeStats->recordRenderEngineDuration(std::chrono::nanoseconds(4ms).count(),
+                                           std::chrono::nanoseconds(6ms).count());
+    mTimeStats->setPresentFenceGlobal(
+            std::make_shared<FenceTime>(std::chrono::nanoseconds(1ms).count()));
 
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
-                                     JankType::SurfaceFlingerCpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
-                                     JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
-                                     JankType::AppDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::DisplayHAL, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::AppDeadlineMissed, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::SurfaceFlingerScheduling, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::PredictionError, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2,
+                                      3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::None, 1, 2, 3});
 
     EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
 
@@ -865,11 +855,6 @@
     EXPECT_THAT(result, HasSubstr("compositionStrategyChanges = 0"));
     EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms"));
     EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms"));
-    EXPECT_THAT(result, HasSubstr("jankyFrames = 0"));
-    EXPECT_THAT(result, HasSubstr("sfLongCpuJankyFrames = 0"));
-    EXPECT_THAT(result, HasSubstr("sfLongGpuJankyFrames = 0"));
-    EXPECT_THAT(result, HasSubstr("sfUnattributedJankyFrame = 0"));
-    EXPECT_THAT(result, HasSubstr("appUnattributedJankyFrame = 0"));
 }
 
 TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
@@ -1000,11 +985,23 @@
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
 
-    mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerCpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::DisplayHAL);
-    mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed);
-    mTimeStats->incrementJankyFrames(JankType::None);
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::DisplayHAL, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::AppDeadlineMissed, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::SurfaceFlingerScheduling, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::PredictionError, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2,
+                                      3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::None, 1, 2, 3});
 
     EXPECT_THAT(mDelegate->mAtomTags,
                 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
@@ -1015,6 +1012,8 @@
     std::string expectedFrameDuration = buildExpectedHistogramBytestring({2}, {1});
     std::string expectedRenderEngineTiming = buildExpectedHistogramBytestring({1, 2}, {1, 1});
     std::string expectedEmptyHistogram = buildExpectedHistogramBytestring({}, {});
+    std::string expectedSfDeadlineMissed = buildExpectedHistogramBytestring({1}, {7});
+    std::string expectedSfPredictionErrors = buildExpectedHistogramBytestring({2}, {7});
 
     {
         InSequence seq;
@@ -1038,27 +1037,29 @@
                                                              expectedRenderEngineTiming.c_str(),
                                                      expectedRenderEngineTiming.size()),
                                              expectedRenderEngineTiming.size()));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 5));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 4));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 8));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 7));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 2));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0));
         EXPECT_CALL(*mDelegate,
                     statsEventWriteByteArray(mDelegate->mEvent,
-                                             BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(),
-                                                     expectedEmptyHistogram.size()),
-                                             expectedEmptyHistogram.size()));
+                                             BytesEq((const uint8_t*)
+                                                             expectedSfDeadlineMissed.c_str(),
+                                                     expectedSfDeadlineMissed.size()),
+                                             expectedSfDeadlineMissed.size()));
         EXPECT_CALL(*mDelegate,
                     statsEventWriteByteArray(mDelegate->mEvent,
-                                             BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(),
-                                                     expectedEmptyHistogram.size()),
-                                             expectedEmptyHistogram.size()));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
+                                             BytesEq((const uint8_t*)
+                                                             expectedSfPredictionErrors.c_str(),
+                                                     expectedSfPredictionErrors.size()),
+                                             expectedSfPredictionErrors.size()));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0));
 
         EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
     }
@@ -1091,14 +1092,23 @@
     }
     insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
 
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
-                                     JankType::SurfaceFlingerCpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
-                                     JankType::SurfaceFlingerGpuDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
-                                     JankType::AppDeadlineMissed);
-    mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::DisplayHAL, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::AppDeadlineMissed, 1, 2, 3});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::SurfaceFlingerScheduling, 1, 2, 2});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::PredictionError, 1, 2, 2});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2,
+                                      2});
+    mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
+                                      JankType::None, 1, 2, 3});
 
     EXPECT_THAT(mDelegate->mAtomTags,
                 UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
@@ -1113,7 +1123,7 @@
     std::string expectedDesiredToPresent = buildExpectedHistogramBytestring({1}, {1});
     std::string expectedPostToAcquire = buildExpectedHistogramBytestring({1}, {1});
     std::string expectedFrameRateOverride = frameRateVoteToProtoByteString(0.0, 0, 0);
-    std::string expectedEmptyHistogram = buildExpectedHistogramBytestring({}, {});
+    std::string expectedAppDeadlineMissed = buildExpectedHistogramBytestring({3, 2}, {4, 3});
     {
         InSequence seq;
         EXPECT_CALL(*mDelegate,
@@ -1161,17 +1171,17 @@
         EXPECT_CALL(*mDelegate,
                     statsEventWriteInt64(mDelegate->mEvent, BAD_DESIRED_PRESENT_FRAMES));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, UID_0));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 5));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 4));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 8));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 7));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 2));
         EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
-        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 1));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0));
         EXPECT_CALL(*mDelegate,
                     statsEventWriteByteArray(mDelegate->mEvent,
                                              BytesEq((const uint8_t*)
@@ -1180,9 +1190,10 @@
                                              expectedFrameRateOverride.size()));
         EXPECT_CALL(*mDelegate,
                     statsEventWriteByteArray(mDelegate->mEvent,
-                                             BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(),
-                                                     expectedEmptyHistogram.size()),
-                                             expectedEmptyHistogram.size()));
+                                             BytesEq((const uint8_t*)
+                                                             expectedAppDeadlineMissed.c_str(),
+                                                     expectedAppDeadlineMissed.size()),
+                                             expectedAppDeadlineMissed.size()));
 
         EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
     }
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
new file mode 100644
index 0000000..dbadf75
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+#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 TransactionFrameTracerTest : public testing::Test {
+public:
+    TransactionFrameTracerTest() {
+        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);
+    }
+
+    ~TransactionFrameTracerTest() {
+        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();
+        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 BLASTTransactionSendsFrameTracerEvents() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+
+        sp<Fence> fence(new Fence());
+        sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+        int32_t layerId = layer->getSequence();
+        uint64_t bufferId = buffer->getId();
+        uint64_t frameNumber = 5;
+        nsecs_t dequeueTime = 10;
+        nsecs_t postTime = 20;
+        EXPECT_CALL(*mFlinger.getFrameTracer(), traceNewLayer(layerId, "buffer-state-layer"));
+        EXPECT_CALL(*mFlinger.getFrameTracer(),
+                    traceTimestamp(layerId, bufferId, frameNumber, dequeueTime,
+                                   FrameTracer::FrameEvent::DEQUEUE, /*duration*/ 0));
+        EXPECT_CALL(*mFlinger.getFrameTracer(),
+                    traceTimestamp(layerId, bufferId, frameNumber, postTime,
+                                   FrameTracer::FrameEvent::QUEUE, /*duration*/ 0));
+        layer->setBuffer(buffer, fence, postTime, /*desiredPresentTime*/ 30, false, mClientCache,
+                         frameNumber, dequeueTime, FrameTimelineInfo{});
+
+        commitTransaction(layer.get());
+        bool computeVisisbleRegions;
+        nsecs_t latchTime = 25;
+        EXPECT_CALL(*mFlinger.getFrameTracer(),
+                    traceFence(layerId, bufferId, frameNumber, _,
+                               FrameTracer::FrameEvent::ACQUIRE_FENCE, /*startTime*/ 0));
+        EXPECT_CALL(*mFlinger.getFrameTracer(),
+                    traceTimestamp(layerId, bufferId, frameNumber, latchTime,
+                                   FrameTracer::FrameEvent::LATCH, /*duration*/ 0));
+        layer->updateTexImage(computeVisisbleRegions, latchTime, /*expectedPresentTime*/ 0);
+
+        auto glDoneFence = fenceFactory.createFenceTimeForTest(fence);
+        auto presentFence = fenceFactory.createFenceTimeForTest(fence);
+        CompositorTiming compositorTiming;
+        EXPECT_CALL(*mFlinger.getFrameTracer(),
+                    traceFence(layerId, bufferId, frameNumber, presentFence,
+                               FrameTracer::FrameEvent::PRESENT_FENCE, /*startTime*/ 0));
+        layer->onPostComposition(nullptr, glDoneFence, presentFence, compositorTiming);
+    }
+};
+
+TEST_F(TransactionFrameTracerTest, BLASTTransactionSendsFrameTracerEvents) {
+    BLASTTransactionSendsFrameTracerEvents();
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index aa6798d..bf9ec39 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -157,8 +157,10 @@
         sp<Fence> fence2(new Fence());
         auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
         sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+        nsecs_t start = systemTime();
         layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
                          {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        nsecs_t end = systemTime();
         acquireFence2->signalForTest(12);
 
         EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
@@ -171,6 +173,9 @@
 
         EXPECT_EQ(1, droppedSurfaceFrame->getToken());
         EXPECT_EQ(PresentState::Dropped, droppedSurfaceFrame->getPresentState());
+        EXPECT_EQ(0u, droppedSurfaceFrame->getActuals().endTime);
+        auto dropTime = droppedSurfaceFrame->getDropTime();
+        EXPECT_TRUE(dropTime > start && dropTime < end);
 
         EXPECT_EQ(1, presentedSurfaceFrame->getToken());
         EXPECT_EQ(PresentState::Presented, presentedSurfaceFrame->getPresentState());
@@ -328,6 +333,41 @@
         EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState());
         EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime);
     }
+
+    void PendingSurfaceFramesRemovedAfterClassification() {
+        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});
+        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);
+
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        auto& presentedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+        commitTransaction(layer.get());
+        bool computeVisisbleRegions;
+        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+
+        // Both the droppedSurfaceFrame and presentedSurfaceFrame should be in
+        // pendingJankClassifications.
+        EXPECT_EQ(2u, layer->mPendingJankClassifications.size());
+        presentedSurfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11),
+                                         /*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0);
+        layer->releasePendingBuffer(25);
+
+        EXPECT_EQ(0u, layer->mPendingJankClassifications.size());
+    }
 };
 
 TEST_F(TransactionSurfaceFrameTest, PresentedBufferlessSurfaceFrame) {
@@ -364,4 +404,7 @@
     MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken();
 }
 
+TEST_F(TransactionSurfaceFrameTest, PendingSurfaceFramesRemovedAfterClassification) {
+    PendingSurfaceFramesRemovedAfterClassification();
+}
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 40437bf..485b4ac 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -33,7 +33,7 @@
     MOCK_METHOD0(onScreenReleased, void());
     MOCK_METHOD0(onScreenAcquired, void());
     MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
-    MOCK_METHOD3(onConfigChanged, void(PhysicalDisplayId, DisplayModeId, nsecs_t));
+    MOCK_METHOD3(onModeChanged, void(PhysicalDisplayId, DisplayModeId, nsecs_t));
     MOCK_METHOD2(onFrameRateOverridesChanged,
                  void(PhysicalDisplayId, std::vector<FrameRateOverride>));
     MOCK_CONST_METHOD1(dump, void(std::string&));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
index 0a6a9f4..44b9b73 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
@@ -31,7 +31,7 @@
 
     MOCK_METHOD0(onBootFinished, void());
     MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr<frametimeline::SurfaceFrame>));
-    MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, nsecs_t));
+    MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, Fps));
     MOCK_METHOD2(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&));
 };
 
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 99ec353..3e4a0b8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -48,10 +48,11 @@
     MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t));
     MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t));
     MOCK_METHOD3(setAcquireFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
-    MOCK_METHOD3(setPresentTime, void(int32_t, uint64_t, nsecs_t));
-    MOCK_METHOD3(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
-    MOCK_METHOD1(incrementJankyFrames, void(int32_t));
-    MOCK_METHOD3(incrementJankyFrames, void(uid_t, const std::string&, int32_t));
+    MOCK_METHOD5(setPresentTime, void(int32_t, uint64_t, nsecs_t, Fps, std::optional<Fps>));
+    MOCK_METHOD5(setPresentFence,
+                 void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&, Fps,
+                      std::optional<Fps>));
+    MOCK_METHOD1(incrementJankyFrames, void(const JankyFramesInfo&));
     MOCK_METHOD1(onDestroy, void(int32_t));
     MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t));
     MOCK_METHOD1(setPowerMode,
diff --git a/services/surfaceflinger/tests/vsync/Android.bp b/services/surfaceflinger/tests/vsync/Android.bp
index 6a89945..bae9796 100644
--- a/services/surfaceflinger/tests/vsync/Android.bp
+++ b/services/surfaceflinger/tests/vsync/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "test-vsync-events",
     defaults: ["surfaceflinger_defaults"],
diff --git a/services/surfaceflinger/tests/waitforvsync/Android.bp b/services/surfaceflinger/tests/waitforvsync/Android.bp
index cb6d0fd..ffed4d7 100644
--- a/services/surfaceflinger/tests/waitforvsync/Android.bp
+++ b/services/surfaceflinger/tests/waitforvsync/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "test-waitforvsync",
     cflags: [
diff --git a/services/utils/Android.bp b/services/utils/Android.bp
index f3d2bc9..81e1232 100644
--- a/services/utils/Android.bp
+++ b/services/utils/Android.bp
@@ -15,6 +15,15 @@
 //
 // Static library used in testing and executables
 //
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
     name: "libserviceutils",
 
diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp
index f21254c..54cf5b7 100644
--- a/services/utils/tests/Android.bp
+++ b/services/utils/tests/Android.bp
@@ -14,6 +14,15 @@
 
 // Build unit tests.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "prioritydumper_test",
     test_suites: ["device-tests"],
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index 96b76ba..f85fa10 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -77,6 +77,8 @@
     MOCK_METHOD(Status, getSupportedAlwaysOnEffects, (std::vector<Effect> * ret), (override));
     MOCK_METHOD(Status, alwaysOnEnable, (int32_t id, Effect e, EffectStrength s), (override));
     MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override));
+    MOCK_METHOD(Status, getQFactor, (float * ret), (override));
+    MOCK_METHOD(Status, getResonantFrequency, (float * ret), (override));
     MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
     MOCK_METHOD(std::string, getInterfaceHash, (), (override));
     MOCK_METHOD(IBinder*, onAsBinder, (), (override));
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
index dd71a6a..bcfd15d 100644
--- a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
@@ -71,6 +71,8 @@
     MOCK_METHOD(Status, getSupportedAlwaysOnEffects, (std::vector<Effect> * ret), (override));
     MOCK_METHOD(Status, alwaysOnEnable, (int32_t id, Effect e, EffectStrength s), (override));
     MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override));
+    MOCK_METHOD(Status, getQFactor, (float * ret), (override));
+    MOCK_METHOD(Status, getResonantFrequency, (float * ret), (override));
     MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
     MOCK_METHOD(std::string, getInterfaceHash, (), (override));
     MOCK_METHOD(IBinder*, onAsBinder, (), (override));
diff --git a/services/vr/Android.bp b/services/vr/Android.bp
index 80df479..980dcf4 100644
--- a/services/vr/Android.bp
+++ b/services/vr/Android.bp
@@ -1,3 +1,13 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 subdirs = [
   "*",
 ]
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 7097e7a..8523bb2 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -12,6 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 sharedLibraries = [
     "libbase",
     "libcutils",
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 3728731..866007e 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libvr_hwc-hal",
 
diff --git a/services/vr/hardware_composer/aidl/Android.bp b/services/vr/hardware_composer/aidl/Android.bp
index a1d5392..98afdec 100644
--- a/services/vr/hardware_composer/aidl/Android.bp
+++ b/services/vr/hardware_composer/aidl/Android.bp
@@ -1,3 +1,14 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
     name: "libvr_hwc-binder",
     srcs: [
diff --git a/services/vr/performanced/Android.bp b/services/vr/performanced/Android.bp
index 0ef8cc4..5eca88b 100644
--- a/services/vr/performanced/Android.bp
+++ b/services/vr/performanced/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-MIT
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "performanced_defaults",
     static_libs: [
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index 9cf4905..f2ec5a4 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -2,6 +2,15 @@
 
 // Touchpad implementation.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 src = [
     "EvdevInjector.cpp",
     "VirtualTouchpadEvdev.cpp",
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index 4934970..33599ea 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -14,6 +14,16 @@
 
 // This module makes the Vulkan libhardware HAL headers available, for
 // the loader and for HAL/driver implementations.
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_headers {
     name: "hwvulkan_headers",
     vendor_available: true,
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 1d29bab..67cd875 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -13,6 +13,15 @@
 // limitations under the License.
 
 // Headers module is in external/vulkan-headers/Android.bp.
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 ndk_library {
     name: "libvulkan",
     symbol_file: "libvulkan.map.txt",
diff --git a/vulkan/nulldrv/Android.bp b/vulkan/nulldrv/Android.bp
index ba02504..0daad9c 100644
--- a/vulkan/nulldrv/Android.bp
+++ b/vulkan/nulldrv/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     // Real drivers would set this to vulkan.$(TARGET_BOARD_PLATFORM)
     name: "vulkan.default",
diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp
index 8528898..fa0258b 100644
--- a/vulkan/vkjson/Android.bp
+++ b/vulkan/vkjson/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_shared {
     name: "libvkjson",
     srcs: [