Merge "blast: default to surface damage to invalid"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 587d25f..5186ad3 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -171,6 +171,7 @@
         { OPT,      "events/clk/clk_disable/enable" },
         { OPT,      "events/clk/clk_enable/enable" },
         { OPT,      "events/power/cpu_frequency_limits/enable" },
+        { OPT,      "events/power/suspend_resume/enable" },
     } },
     { "membus",     "Memory Bus Utilization", 0, {
         { REQ,      "events/memory_bus/enable" },
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index f1426b6..6e460a0 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -49,6 +49,8 @@
     chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
     chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_frequency/enable
     chmod 0666 /sys/kernel/tracing/events/power/gpu_frequency/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/power/suspend_resume/enable
+    chmod 0666 /sys/kernel/tracing/events/power/suspend_resume/enable
     chmod 0666 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
     chmod 0666 /sys/kernel/tracing/events/cpufreq_interactive/enable
     chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 3a0aa95..eb2dad5 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -44,10 +44,12 @@
 #include <unistd.h>
 
 #include <chrono>
+#include <cmath>
 #include <fstream>
 #include <functional>
 #include <future>
 #include <memory>
+#include <numeric>
 #include <regex>
 #include <set>
 #include <string>
@@ -1232,6 +1234,45 @@
     }
 }
 
+static void DumpExternalFragmentationInfo() {
+    struct stat st;
+    if (stat("/proc/buddyinfo", &st) != 0) {
+        MYLOGE("Unable to dump external fragmentation info\n");
+        return;
+    }
+
+    printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
+    std::ifstream ifs("/proc/buddyinfo");
+    auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
+    for (std::string line; std::getline(ifs, line);) {
+        std::smatch match_results;
+        if (std::regex_match(line, match_results, unusable_index_regex)) {
+            std::stringstream free_pages(std::string{match_results[3]});
+            std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
+                                                  std::istream_iterator<int>());
+
+            int total_free_pages = 0;
+            for (size_t i = 0; i < free_pages_per_order.size(); i++) {
+                total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
+            }
+
+            printf("Node %s, zone %8s", match_results[1].str().c_str(),
+                   match_results[2].str().c_str());
+
+            int usable_free_pages = total_free_pages;
+            for (size_t i = 0; i < free_pages_per_order.size(); i++) {
+                auto unusable_index = (total_free_pages - usable_free_pages) /
+                        static_cast<double>(total_free_pages);
+                printf(" %5.3f", unusable_index);
+                usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
+            }
+
+            printf("\n");
+        }
+    }
+    printf("\n");
+}
+
 // Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
 // via the consent they are shown. Ignores other errors that occur while running various
 // commands. The consent checking is currently done around long running tasks, which happen to
@@ -1258,7 +1299,7 @@
     DumpFile("ZONEINFO", "/proc/zoneinfo");
     DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
     DumpFile("BUDDYINFO", "/proc/buddyinfo");
-    DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
+    DumpExternalFragmentationInfo();
 
     DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
     DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
@@ -1505,6 +1546,8 @@
 static void DumpstateRadioCommon() {
     DumpIpTablesAsRoot();
 
+    ds.AddDir(LOGPERSIST_DATA_DIR, false);
+
     if (!DropRootUser()) {
         return;
     }
@@ -1515,6 +1558,7 @@
     DoKmsg();
     DumpIpAddrAndRules();
     dump_route_tables();
+    DumpHals();
 
     RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
                CommandOptions::WithTimeout(10).Build());
@@ -1584,8 +1628,6 @@
     RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
                SEC_TO_MSEC(10));
 
-    DumpHals();
-
     printf("========================================================\n");
     printf("== dumpstate: done (id %d)\n", ds.id_);
     printf("========================================================\n");
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 73780ec..0212bc5 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -275,7 +275,7 @@
             writer.StartEntry("primary.prof", ZipWriter::kCompress);
             writer.FinishEntry();
             writer.Finish();
-            close(fd);
+            fclose(file);
           }
 
         // Create the app user data.
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 5f7dc25..f35f360 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -98,18 +98,12 @@
         return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
     }
 
+    // implicitly unlinked when the binder is removed
     if (OK != binder->linkToDeath(this)) {
         LOG(ERROR) << "Could not linkToDeath when adding " << name;
         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
     }
 
-    auto it = mNameToService.find(name);
-    if (it != mNameToService.end()) {
-        if (OK != it->second.binder->unlinkToDeath(this)) {
-            LOG(WARNING) << "Could not unlinkToDeath when adding " << name;
-        }
-    }
-
     mNameToService[name] = Service {
         .binder = binder,
         .allowIsolated = allowIsolated,
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index ad7791e..50f117d 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -40,7 +40,6 @@
     <feature name="android.software.voice_recognizers" notLowRam="true" />
     <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
-    <feature name="android.software.print" />
     <feature name="android.software.companion_device_setup" />
     <feature name="android.software.autofill" />
     <feature name="android.software.cant_save_state" />
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 2def64d..6fba0ac 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -60,6 +60,8 @@
     ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
     /** Alpha: 8 bits. */
     ANDROID_BITMAP_FORMAT_A_8       = 8,
+    /** Each component is stored as a half float. **/
+    ANDROID_BITMAP_FORMAT_RGBA_F16  = 9,
 };
 
 /** Bitmap info, see AndroidBitmap_getInfo(). */
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 1537e69..dec75f5 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -38,7 +38,7 @@
     virtual status_t    transact(   uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
-                                    uint32_t flags = 0);
+                                    uint32_t flags = 0) final;
 
     // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient,
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index e71541b..28599f4 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -45,7 +45,7 @@
     virtual status_t    transact(   uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
-                                    uint32_t flags = 0);
+                                    uint32_t flags = 0) final;
 
     // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient,
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 1beacdf..734a928 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-cc_library {
+cc_library_shared {
     name: "libbinder_ndk",
 
     export_include_dirs: [
         "include_ndk",
-        "include_apex",
+        "include_platform",
     ],
 
     cflags: [
@@ -80,6 +80,6 @@
     symbol_file: "libbinder_ndk.map.txt",
     export_include_dirs: [
         "include_ndk",
-        "include_apex",
+        "include_platform",
     ],
 }
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
similarity index 100%
rename from libs/binder/ndk/include_apex/android/binder_manager.h
rename to libs/binder/ndk/include_platform/android/binder_manager.h
diff --git a/libs/binder/ndk/include_apex/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
similarity index 100%
rename from libs/binder/ndk/include_apex/android/binder_process.h
rename to libs/binder/ndk/include_platform/android/binder_process.h
diff --git a/libs/binder/ndk/include_apex/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
similarity index 100%
rename from libs/binder/ndk/include_apex/android/binder_stability.h
rename to libs/binder/ndk/include_platform/android/binder_stability.h
diff --git a/libs/binder/ndk/stability.cpp b/libs/binder/ndk/stability.cpp
index abafe1f..a5b3ece 100644
--- a/libs/binder/ndk/stability.cpp
+++ b/libs/binder/ndk/stability.cpp
@@ -27,6 +27,10 @@
 #error libbinder_ndk should only be built in a system context
 #endif
 
+#ifdef __ANDROID_NDK__
+#error libbinder_ndk should only be built in a system context
+#endif
+
 // explicit extern because symbol is only declared in header when __ANDROID_VNDK__
 extern "C" void AIBinder_markVendorStability(AIBinder* binder) {
     Stability::markVndk(binder->getBinder().get());
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 8cd4e03..bb1fe2f 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -44,10 +44,10 @@
         "libandroid_runtime_lazy",
         "libbase",
         "libbinder",
+        "libbinder_ndk",
         "libutils",
     ],
     static_libs: [
-        "libbinder_ndk",
         "test_libbinder_ndk_library",
     ],
 }
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index d59a40d..bc457ce 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -142,7 +142,6 @@
     name: "binderStabilityTestIface",
     srcs: [
         "IBinderStabilityTest.aidl",
-        "IBinderStabilityTestSub.aidl",
     ],
 }
 
diff --git a/libs/binder/tests/IBinderStabilityTest.aidl b/libs/binder/tests/IBinderStabilityTest.aidl
index 9559196..36e1c2c 100644
--- a/libs/binder/tests/IBinderStabilityTest.aidl
+++ b/libs/binder/tests/IBinderStabilityTest.aidl
@@ -14,34 +14,32 @@
  * limitations under the License.
  */
 
-import IBinderStabilityTestSub;
-
 // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
 // THIS IS ONLY FOR TESTING!
 interface IBinderStabilityTest {
     // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
     // THIS IS ONLY FOR TESTING!
-    void sendBinder(IBinderStabilityTestSub binder);
+    void sendBinder(IBinder binder);
 
     // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
     // THIS IS ONLY FOR TESTING!
-    void sendAndCallBinder(IBinderStabilityTestSub binder);
+    void sendAndCallBinder(IBinder binder);
 
     // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
     // THIS IS ONLY FOR TESTING!
-    IBinderStabilityTestSub returnNoStabilityBinder();
+    IBinder returnNoStabilityBinder();
 
     // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
     // THIS IS ONLY FOR TESTING!
-    IBinderStabilityTestSub returnLocalStabilityBinder();
+    IBinder returnLocalStabilityBinder();
 
     // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
     // THIS IS ONLY FOR TESTING!
-    IBinderStabilityTestSub returnVintfStabilityBinder();
+    IBinder returnVintfStabilityBinder();
 
     // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
     // THIS IS ONLY FOR TESTING!
-    IBinderStabilityTestSub returnVendorStabilityBinder();
+    IBinder returnVendorStabilityBinder();
 }
 // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
 // THIS IS ONLY FOR TESTING!
diff --git a/libs/binder/tests/IBinderStabilityTestSub.aidl b/libs/binder/tests/IBinderStabilityTestSub.aidl
deleted file mode 100644
index a81ebf9..0000000
--- a/libs/binder/tests/IBinderStabilityTestSub.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-interface IBinderStabilityTestSub {
-    void userDefinedTransaction();
-}
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index 936b821..0336b9e 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -26,9 +26,7 @@
 
 #include <sys/prctl.h>
 
-#include "aidl/BnBinderStabilityTestSub.h"
 #include "aidl/BnBinderStabilityTest.h"
-#include "BnBinderStabilityTestSub.h"
 #include "BnBinderStabilityTest.h"
 
 using namespace android;
@@ -36,167 +34,217 @@
 using android::binder::Status;
 using android::internal::Stability; // for testing only!
 
-const String16 kNoStabilityServer = String16("binder_stability_test_service_low");
-const String16 kCompilationUnitServer = String16("binder_stability_test_service_compl");
-const String16 kVintfServer = String16("binder_stability_test_service_vintf");
+const String16 kSystemStabilityServer = String16("binder_stability_test_service_system");
 
-const String16 kCompilationUnitNdkServer = String16("binder_stability_test_service_compl");
-
-class BadStabilityTestSub : public BnBinderStabilityTestSub {
+// This is handwritten so that we can test different stability levels w/o having the AIDL
+// compiler assign them. Hand-writing binder interfaces is considered a bad practice
+// sanity reasons. YOU SHOULD DEFINE AN AIDL INTERFACE INSTEAD!
+class BadStableBinder : public BBinder {
 public:
-    Status userDefinedTransaction() {
-        return Status::ok();
+    static constexpr uint32_t USER_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION;
+    static String16 kDescriptor;
+
+    bool gotUserTransaction = false;
+
+    static status_t doUserTransaction(const sp<IBinder>& binder) {
+        Parcel data, reply;
+        data.writeInterfaceToken(kDescriptor);
+        return binder->transact(USER_TRANSACTION, data, &reply, 0/*flags*/);
     }
 
-    static sp<IBinderStabilityTestSub> system() {
-        sp<BnBinderStabilityTestSub> iface = new BadStabilityTestSub();
-        // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
-        // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
-        Stability::markCompilationUnit(iface.get()); // <- BAD, NO! DO NOT COPY
+    status_t onTransact(uint32_t code,
+            const Parcel& data, Parcel* reply, uint32_t flags) override {
+        if (code == USER_TRANSACTION) {
+            // not interested in this kind of stability. Make sure
+            // we have a test failure
+            LOG_ALWAYS_FATAL_IF(!data.enforceInterface(kDescriptor));
+
+            gotUserTransaction = true;
+
+            ALOGE("binder stability: Got user transaction");
+            return OK;
+        }
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+
+    static sp<BadStableBinder> undef() {
+        sp<BadStableBinder> iface = new BadStableBinder();
         return iface;
     }
 
-    static sp<IBinderStabilityTestSub> vintf() {
-        sp<BnBinderStabilityTestSub> iface = new BadStabilityTestSub();
-        // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
-        // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
-        Stability::markVintf(iface.get()); // <- BAD, NO! DO NOT COPY
+    static sp<BadStableBinder> system() {
+        sp<BadStableBinder> iface = new BadStableBinder();
+        Stability::markCompilationUnit(iface.get()); // <- for test only
         return iface;
     }
 
-    static sp<IBinderStabilityTestSub> vendor() {
-        sp<BnBinderStabilityTestSub> iface = new BadStabilityTestSub();
-        // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
-        // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
-        Stability::markVndk(iface.get()); // <- BAD, NO! DO NOT COPY
+    static sp<BadStableBinder> vintf() {
+        sp<BadStableBinder> iface = new BadStableBinder();
+        Stability::markVintf(iface.get()); // <- for test only
+        return iface;
+    }
+
+    static sp<BadStableBinder> vendor() {
+        sp<BadStableBinder> iface = new BadStableBinder();
+        Stability::markVndk(iface.get()); // <- for test only
         return iface;
     }
 };
+String16 BadStableBinder::kDescriptor = String16("BadStableBinder.test");
 
 // NO! NO! NO! Do not even think of doing something like this!
 // This is for testing! If a class like this was actually used in production,
 // it would ruin everything!
-class BadStabilityTester : public BnBinderStabilityTest {
+class MyBinderStabilityTest : public BnBinderStabilityTest {
 public:
-    Status sendBinder(const sp<IBinderStabilityTestSub>& /*binder*/) override {
+    Status sendBinder(const sp<IBinder>& /*binder*/) override {
         return Status::ok();
     }
-    Status sendAndCallBinder(const sp<IBinderStabilityTestSub>& binder) override {
-        Stability::debugLogStability("sendAndCallBinder got binder", IInterface::asBinder(binder));
-        return binder->userDefinedTransaction();
+    Status sendAndCallBinder(const sp<IBinder>& binder) override {
+        Stability::debugLogStability("sendAndCallBinder got binder", binder);
+        return Status::fromExceptionCode(BadStableBinder::doUserTransaction(binder));
     }
-    Status returnNoStabilityBinder(sp<IBinderStabilityTestSub>* _aidl_return) override {
-        *_aidl_return = new BadStabilityTestSub();
+    Status returnNoStabilityBinder(sp<IBinder>* _aidl_return) override {
+        *_aidl_return = BadStableBinder::undef();
         return Status::ok();
     }
-    Status returnLocalStabilityBinder(sp<IBinderStabilityTestSub>* _aidl_return) override {
-        *_aidl_return = BadStabilityTestSub::system();
+    Status returnLocalStabilityBinder(sp<IBinder>* _aidl_return) override {
+        *_aidl_return = BadStableBinder::system();
         return Status::ok();
     }
-    Status returnVintfStabilityBinder(sp<IBinderStabilityTestSub>* _aidl_return) override {
-        *_aidl_return = BadStabilityTestSub::vintf();
+    Status returnVintfStabilityBinder(sp<IBinder>* _aidl_return) override {
+        *_aidl_return = BadStableBinder::vintf();
         return Status::ok();
     }
-    Status returnVendorStabilityBinder(sp<IBinderStabilityTestSub>* _aidl_return) override {
-        *_aidl_return = BadStabilityTestSub::vendor();
+    Status returnVendorStabilityBinder(sp<IBinder>* _aidl_return) override {
+        *_aidl_return = BadStableBinder::vendor();
         return Status::ok();
     }
 };
 
-void checkSystemStabilityBinder(const sp<IBinderStabilityTest>& complServer) {
-    EXPECT_TRUE(complServer->sendBinder(new BadStabilityTestSub()).isOk());
-    EXPECT_TRUE(complServer->sendBinder(BadStabilityTestSub::system()).isOk());
-    EXPECT_TRUE(complServer->sendBinder(BadStabilityTestSub::vintf()).isOk());
-    EXPECT_TRUE(complServer->sendBinder(BadStabilityTestSub::vendor()).isOk());
+TEST(BinderStability, CantCallVendorBinderInSystemContext) {
+    sp<IBinder> serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer);
+    auto server = interface_cast<IBinderStabilityTest>(serverBinder);
 
-    EXPECT_TRUE(complServer->sendAndCallBinder(new BadStabilityTestSub()).isOk());
-    EXPECT_TRUE(complServer->sendAndCallBinder(BadStabilityTestSub::system()).isOk());
-    EXPECT_TRUE(complServer->sendAndCallBinder(BadStabilityTestSub::vintf()).isOk());
+    ASSERT_NE(nullptr, server.get());
+    ASSERT_NE(nullptr, IInterface::asBinder(server)->remoteBinder());
 
-    // !!! user-defined transaction may not be stable for remote server !!!
-    EXPECT_FALSE(complServer->sendAndCallBinder(BadStabilityTestSub::vendor()).isOk());
+    EXPECT_TRUE(server->sendBinder(BadStableBinder::undef()).isOk());
+    EXPECT_TRUE(server->sendBinder(BadStableBinder::system()).isOk());
+    EXPECT_TRUE(server->sendBinder(BadStableBinder::vintf()).isOk());
+    EXPECT_TRUE(server->sendBinder(BadStableBinder::vendor()).isOk());
 
-    sp<IBinderStabilityTestSub> out;
-    EXPECT_TRUE(complServer->returnNoStabilityBinder(&out).isOk());
+    {
+        sp<BadStableBinder> binder = BadStableBinder::undef();
+        EXPECT_TRUE(server->sendAndCallBinder(binder).isOk());
+        EXPECT_TRUE(binder->gotUserTransaction);
+    }
+    {
+        sp<BadStableBinder> binder = BadStableBinder::system();
+        EXPECT_TRUE(server->sendAndCallBinder(binder).isOk());
+        EXPECT_TRUE(binder->gotUserTransaction);
+    }
+    {
+        sp<BadStableBinder> binder = BadStableBinder::vintf();
+        EXPECT_TRUE(server->sendAndCallBinder(binder).isOk());
+        EXPECT_TRUE(binder->gotUserTransaction);
+    }
+    {
+        // !!! user-defined transaction may not be stable for remote server !!!
+        // !!! so, it does not work !!!
+        sp<BadStableBinder> binder = BadStableBinder::vendor();
+        EXPECT_EQ(BAD_TYPE, server->sendAndCallBinder(binder).exceptionCode());
+        EXPECT_FALSE(binder->gotUserTransaction);
+    }
+
+    sp<IBinder> out;
+    EXPECT_TRUE(server->returnNoStabilityBinder(&out).isOk());
     ASSERT_NE(nullptr, out.get());
-    EXPECT_EQ(OK, IInterface::asBinder(out)->pingBinder());
-    EXPECT_TRUE(out->userDefinedTransaction().isOk());
+    EXPECT_EQ(OK, out->pingBinder());
+    EXPECT_EQ(OK, BadStableBinder::doUserTransaction(out));
 
-    EXPECT_TRUE(complServer->returnLocalStabilityBinder(&out).isOk());
+    EXPECT_TRUE(server->returnLocalStabilityBinder(&out).isOk());
     ASSERT_NE(nullptr, out.get());
-    EXPECT_EQ(OK, IInterface::asBinder(out)->pingBinder());
-    EXPECT_TRUE(out->userDefinedTransaction().isOk());
+    EXPECT_EQ(OK, out->pingBinder());
+    EXPECT_EQ(OK, BadStableBinder::doUserTransaction(out));
 
-    EXPECT_TRUE(complServer->returnVintfStabilityBinder(&out).isOk());
+    EXPECT_TRUE(server->returnVintfStabilityBinder(&out).isOk());
     ASSERT_NE(nullptr, out.get());
-    EXPECT_EQ(OK, IInterface::asBinder(out)->pingBinder());
-    EXPECT_TRUE(out->userDefinedTransaction().isOk());
+    EXPECT_EQ(OK, out->pingBinder());
+    EXPECT_EQ(OK, BadStableBinder::doUserTransaction(out));
 
-    EXPECT_TRUE(complServer->returnVendorStabilityBinder(&out).isOk());
+    EXPECT_TRUE(server->returnVendorStabilityBinder(&out).isOk());
     ASSERT_NE(nullptr, out.get());
 
     // !!! libbinder-defined transaction works !!!
-    EXPECT_EQ(OK, IInterface::asBinder(out)->pingBinder());
+    EXPECT_EQ(OK, out->pingBinder());
 
     // !!! user-defined transaction may not be stable !!!
-    EXPECT_FALSE(out->userDefinedTransaction().isOk());
+    // !!! so, it does not work !!!
+    EXPECT_EQ(BAD_TYPE, BadStableBinder::doUserTransaction(out));
 }
 
-TEST(BinderStability, RemoteNoStabilityServer) {
-    sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kNoStabilityServer);
-    auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+// This is handwritten so that we can test different stability levels w/o having the AIDL
+// compiler assign them. Hand-writing binder interfaces is considered a bad practice
+// sanity reasons. YOU SHOULD DEFINE AN AIDL INTERFACE INSTEAD!
 
-    ASSERT_NE(nullptr, remoteServer.get());
-    ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
-
-    checkSystemStabilityBinder(remoteServer);
-}
-
-TEST(BinderStability, RemoteLowStabilityServer) {
-    sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kCompilationUnitServer);
-    auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
-
-    ASSERT_NE(nullptr, remoteServer.get());
-    ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
-
-    checkSystemStabilityBinder(remoteServer);
-}
-
-TEST(BinderStability, RemoteVintfServer) {
-    sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kVintfServer);
-    auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
-
-    ASSERT_NE(nullptr, remoteServer.get());
-    ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
-
-    checkSystemStabilityBinder(remoteServer);
-}
-
-class NdkBadStabilityTestSub : public aidl::BnBinderStabilityTestSub {
-    ScopedAStatus userDefinedTransaction() {
-        return ScopedAStatus::ok();
-    }
+struct NdkBinderStable_DataClass {
+    bool gotUserTransaction = false;
 };
+void* NdkBadStableBinder_Class_onCreate(void* args) {
+    LOG_ALWAYS_FATAL_IF(args != nullptr, "Takes no args");
+    return static_cast<void*>(new NdkBinderStable_DataClass);
+}
+void NdkBadStableBinder_Class_onDestroy(void* userData) {
+    delete static_cast<NdkBinderStable_DataClass*>(userData);
+}
+NdkBinderStable_DataClass* NdkBadStableBinder_getUserData(AIBinder* binder) {
+    LOG_ALWAYS_FATAL_IF(binder == nullptr);
+    void* userData = AIBinder_getUserData(binder);
+    LOG_ALWAYS_FATAL_IF(userData == nullptr, "null data - binder is remote?");
+
+    return static_cast<NdkBinderStable_DataClass*>(userData);
+}
+binder_status_t NdkBadStableBinder_Class_onTransact(
+    AIBinder* binder, transaction_code_t code, const AParcel* /*in*/, AParcel* /*out*/) {
+
+    if (code == BadStableBinder::USER_TRANSACTION) {
+        ALOGE("ndk binder stability: Got user transaction");
+        NdkBadStableBinder_getUserData(binder)->gotUserTransaction = true;
+        return STATUS_OK;
+    }
+
+    return STATUS_UNKNOWN_TRANSACTION;
+}
+
+static AIBinder_Class* kNdkBadStableBinder =
+    AIBinder_Class_define(String8(BadStableBinder::kDescriptor).c_str(),
+                          NdkBadStableBinder_Class_onCreate,
+                          NdkBadStableBinder_Class_onDestroy,
+                          NdkBadStableBinder_Class_onTransact);
+
 // for testing only to get around __ANDROID_VNDK__ guard.
 extern "C" void AIBinder_markVendorStability(AIBinder* binder); // <- BAD DO NOT COPY
 
-TEST(BinderStability, NdkClientOfRemoteServer) {
+TEST(BinderStability, NdkCantCallVendorBinderInSystemContext) {
     SpAIBinder binder = SpAIBinder(AServiceManager_getService(
-        String8(kCompilationUnitServer).c_str()));
+        String8(kSystemStabilityServer).c_str()));
 
     std::shared_ptr<aidl::IBinderStabilityTest> remoteServer =
         aidl::IBinderStabilityTest::fromBinder(binder);
 
     ASSERT_NE(nullptr, remoteServer.get());
 
-    std::shared_ptr<aidl::IBinderStabilityTestSub> vendor = SharedRefBase::make<NdkBadStabilityTestSub>();
+    SpAIBinder comp = SpAIBinder(AIBinder_new(kNdkBadStableBinder, nullptr /*args*/));
+    EXPECT_TRUE(remoteServer->sendBinder(comp).isOk());
+    EXPECT_TRUE(remoteServer->sendAndCallBinder(comp).isOk());
+    EXPECT_TRUE(NdkBadStableBinder_getUserData(comp.get())->gotUserTransaction);
 
-    // TODO: not ideal: binder must be held once it is marked
-    SpAIBinder vendorBinder = vendor->asBinder();
-    AIBinder_markVendorStability(vendorBinder.get());
-
+    SpAIBinder vendor = SpAIBinder(AIBinder_new(kNdkBadStableBinder, nullptr /*args*/));
+    AIBinder_markVendorStability(vendor.get());
     EXPECT_TRUE(remoteServer->sendBinder(vendor).isOk());
     EXPECT_FALSE(remoteServer->sendAndCallBinder(vendor).isOk());
+    EXPECT_FALSE(NdkBadStableBinder_getUserData(vendor.get())->gotUserTransaction);
 }
 
 class MarksStabilityInConstructor : public BBinder {
@@ -227,6 +275,14 @@
     ASSERT_TRUE(MarksStabilityInConstructor::gDestructed);
 }
 
+TEST(BinderStability, RemarkDies) {
+    ASSERT_DEATH({
+        sp<IBinder> binder = new BBinder();
+        Stability::markCompilationUnit(binder.get()); // <-- only called for tests
+        Stability::markVndk(binder.get()); // <-- only called for tests
+    }, "Should only mark known object.");
+}
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
 
@@ -234,16 +290,8 @@
         // child process
         prctl(PR_SET_PDEATHSIG, SIGHUP);
 
-        sp<IBinder> noStability = new BadStabilityTester;
-        android::defaultServiceManager()->addService(kNoStabilityServer, noStability);
-
-        sp<IBinder> compil = new BadStabilityTester;
-        Stability::markCompilationUnit(compil.get());
-        android::defaultServiceManager()->addService(kCompilationUnitServer, compil);
-
-        sp<IBinder> vintf = new BadStabilityTester;
-        Stability::markVintf(vintf.get());
-        android::defaultServiceManager()->addService(kVintfServer, vintf);
+        sp<IBinder> server = new MyBinderStabilityTest;
+        android::defaultServiceManager()->addService(kSystemStabilityServer, server);
 
         IPCThreadState::self()->joinThreadPool(true);
         exit(1);  // should not reach
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 0e68e62..4c8d52e 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -22,6 +22,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <inttypes.h>
+#include <sys/sysinfo.h>
 
 #include <mutex>
 #include <optional>
@@ -48,6 +49,7 @@
 static std::mutex gInitializedMutex;
 static bool gInitialized = false;
 static uint32_t gNPolicies = 0;
+static uint32_t gNCpus = 0;
 static std::vector<std::vector<uint32_t>> gPolicyFreqs;
 static std::vector<std::vector<uint32_t>> gPolicyCpus;
 static std::set<uint32_t> gAllFreqs;
@@ -85,6 +87,8 @@
     std::lock_guard<std::mutex> guard(gInitializedMutex);
     if (gInitialized) return true;
 
+    gNCpus = get_nprocs_conf();
+
     struct dirent **dirlist;
     const char basepath[] = "/sys/devices/system/cpu/cpufreq";
     int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles);
@@ -140,6 +144,32 @@
 // This function should *not* be called while tracking is already active; doing so is unnecessary
 // and can lead to accounting errors.
 bool startTrackingUidCpuFreqTimes() {
+    if (!initGlobals()) return false;
+
+    unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
+    if (fd < 0) return false;
+
+    for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
+        for (auto &cpu : gPolicyCpus[i]) {
+            if (writeToMapEntry(fd, &cpu, &i, BPF_ANY)) return false;
+        }
+    }
+
+    unique_fd fd2(bpf_obj_get(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
+    if (fd2 < 0) return false;
+    freq_idx_key_t key;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        key.policy = i;
+        for (uint32_t j = 0; j < gPolicyFreqs[i].size(); ++j) {
+            key.freq = gPolicyFreqs[i][j];
+            // Start indexes at 1 so that uninitialized state is distinguishable from lowest freq.
+            // The uid_times map still uses 0-based indexes, and the sched_switch program handles
+            // conversion between them, so this does not affect our map reading code.
+            uint32_t idx = j + 1;
+            if (writeToMapEntry(fd2, &key, &idx, BPF_ANY)) return false;
+        }
+    }
+
     return attachTracepointProgram("sched", "sched_switch") &&
             attachTracepointProgram("power", "cpu_frequency");
 }
@@ -151,27 +181,33 @@
 // where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq.
 std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid) {
     if (!gInitialized && !initGlobals()) return {};
-    time_key_t key = {.uid = uid, .freq = 0};
 
-    std::vector<std::vector<uint64_t>> out(gNPolicies);
-    std::vector<uint32_t> idxs(gNPolicies, 0);
+    std::vector<std::vector<uint64_t>> out;
+    uint32_t maxFreqCount = 0;
+    for (const auto &freqList : gPolicyFreqs) {
+        if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
+        out.emplace_back(freqList.size(), 0);
+    }
 
-    val_t value;
-    for (uint32_t freq : gAllFreqs) {
-        key.freq = freq;
-        int ret = findMapEntry(gMapFd, &key, &value);
-        if (ret) {
-            if (errno == ENOENT)
-                memset(&value.ar, 0, sizeof(value.ar));
-            else
-                return {};
+    std::vector<val_t> vals(gNCpus);
+    time_key_t key = {.uid = uid};
+    for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) {
+        key.bucket = i;
+        if (findMapEntry(gMapFd, &key, vals.data())) {
+            if (errno != ENOENT) return {};
+            continue;
         }
-        for (uint32_t i = 0; i < gNPolicies; ++i) {
-            if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue;
-            uint64_t time = 0;
-            for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu];
-            idxs[i] += 1;
-            out[i].emplace_back(time);
+
+        auto offset = i * FREQS_PER_ENTRY;
+        auto nextOffset = (i + 1) * FREQS_PER_ENTRY;
+        for (uint32_t j = 0; j < gNPolicies; ++j) {
+            if (offset >= gPolicyFreqs[j].size()) continue;
+            auto begin = out[j].begin() + offset;
+            auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY : out[j].end();
+
+            for (const auto &cpu : gPolicyCpus[j]) {
+                std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus<uint64_t>());
+            }
         }
     }
 
@@ -187,47 +223,53 @@
 std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
 getUidsCpuFreqTimes() {
     if (!gInitialized && !initGlobals()) return {};
-
-    int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map");
-    if (fd < 0) return {};
-    BpfMap<time_key_t, val_t> m(fd);
-
-    std::vector<std::unordered_map<uint32_t, uint32_t>> policyFreqIdxs;
-    for (uint32_t i = 0; i < gNPolicies; ++i) {
-        std::unordered_map<uint32_t, uint32_t> freqIdxs;
-        for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j;
-        policyFreqIdxs.emplace_back(freqIdxs);
-    }
+    time_key_t key, prevKey;
     std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map;
-    auto fn = [&map, &policyFreqIdxs](const time_key_t &key, const val_t &val,
-                                             const BpfMap<time_key_t, val_t> &) {
-        if (map.find(key.uid) == map.end()) {
-            map[key.uid].resize(gNPolicies);
-            for (uint32_t i = 0; i < gNPolicies; ++i) {
-                map[key.uid][i].resize(gPolicyFreqs[i].size(), 0);
-            }
-        }
+    if (getFirstMapKey(gMapFd, &key)) {
+        if (errno == ENOENT) return map;
+        return std::nullopt;
+    }
 
-        for (size_t policy = 0; policy < gNPolicies; ++policy) {
-            for (const auto &cpu : gPolicyCpus[policy]) {
-                auto freqIdx = policyFreqIdxs[policy][key.freq];
-                map[key.uid][policy][freqIdx] += val.ar[cpu];
+    std::vector<std::vector<uint64_t>> mapFormat;
+    for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0);
+
+    std::vector<val_t> vals(gNCpus);
+    do {
+        if (findMapEntry(gMapFd, &key, vals.data())) return {};
+        if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat);
+
+        auto offset = key.bucket * FREQS_PER_ENTRY;
+        auto nextOffset = (key.bucket + 1) * FREQS_PER_ENTRY;
+        for (uint32_t i = 0; i < gNPolicies; ++i) {
+            if (offset >= gPolicyFreqs[i].size()) continue;
+            auto begin = map[key.uid][i].begin() + offset;
+            auto end = nextOffset < gPolicyFreqs[i].size() ? begin + FREQS_PER_ENTRY :
+                map[key.uid][i].end();
+            for (const auto &cpu : gPolicyCpus[i]) {
+                std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus<uint64_t>());
             }
         }
-        return android::netdutils::status::ok;
-    };
-    if (isOk(m.iterateWithValue(fn))) return map;
-    return {};
+        prevKey = key;
+    } while (!getNextMapKey(gMapFd, &prevKey, &key));
+    if (errno != ENOENT) return {};
+    return map;
 }
 
 // Clear all time in state data for a given uid. Returns false on error, true otherwise.
 bool clearUidCpuFreqTimes(uint32_t uid) {
     if (!gInitialized && !initGlobals()) return false;
-    time_key_t key = {.uid = uid, .freq = 0};
 
-    std::vector<uint32_t> idxs(gNPolicies, 0);
-    for (auto freq : gAllFreqs) {
-        key.freq = freq;
+    time_key_t key = {.uid = uid};
+
+    uint32_t maxFreqCount = 0;
+    for (const auto &freqList : gPolicyFreqs) {
+        if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
+    }
+
+    val_t zeros = {0};
+    std::vector<val_t> vals(gNCpus, zeros);
+    for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) {
+        if (writeToMapEntry(gMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT) return false;
         if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false;
     }
     return true;
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 6347de1..39007e4 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -126,10 +126,10 @@
         ASSERT_GE(fd, 0);
         time_key_t k;
         ASSERT_FALSE(getFirstMapKey(fd, &k));
-        val_t val;
-        ASSERT_FALSE(findMapEntry(fd, &k, &val));
+        std::vector<val_t> vals(get_nprocs_conf());
+        ASSERT_FALSE(findMapEntry(fd, &k, vals.data()));
         k.uid = uid;
-        ASSERT_FALSE(writeToMapEntry(fd, &k, &val, BPF_NOEXIST));
+        ASSERT_FALSE(writeToMapEntry(fd, &k, vals.data(), BPF_NOEXIST));
     }
     auto times = getUidCpuFreqTimes(uid);
     ASSERT_TRUE(times.has_value());
diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h
index cf66ae7..41d0af0 100644
--- a/libs/cputimeinstate/timeinstate.h
+++ b/libs/cputimeinstate/timeinstate.h
@@ -18,11 +18,18 @@
 
 #define BPF_FS_PATH "/sys/fs/bpf/"
 
+#define FREQS_PER_ENTRY 32
+
 struct time_key_t {
     uint32_t uid;
-    uint32_t freq;
+    uint32_t bucket;
 };
 
 struct val_t {
-    uint64_t ar[100];
+    uint64_t ar[FREQS_PER_ENTRY];
+};
+
+struct freq_idx_key_t {
+    uint32_t policy;
+    uint32_t freq;
 };
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index ff1ba0a..386f731 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -410,6 +410,19 @@
     bgSurface->expectTap(1, 1);
 }
 
+TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) {
+    std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+    // In case we pass the very big inset without any checking.
+    fgSurface->mInputInfo.surfaceInset = INT32_MAX;
+    fgSurface->showAt(100, 100);
+
+    fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); });
+
+    // expect no crash for overflow, and inset size to be clamped to surface size
+    injectTap(202, 202);
+    fgSurface->expectTap(1, 1);
+}
+
 // Ensure we ignore transparent region when getting screen bounds when positioning input frame.
 TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
     std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 019815c..1eb979e 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -48,10 +48,11 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <limits.h>
-#include <sstream>
 #include <stddef.h>
 #include <time.h>
 #include <unistd.h>
+#include <queue>
+#include <sstream>
 
 #include <android-base/chrono_utils.h>
 #include <android-base/stringprintf.h>
@@ -358,7 +359,7 @@
     // Ready to start a new event.
     // If we don't already have a pending event, go grab one.
     if (! mPendingEvent) {
-        if (mInboundQueue.isEmpty()) {
+        if (mInboundQueue.empty()) {
             if (isAppSwitchDue) {
                 // The inbound queue is empty so the app switch key we were waiting
                 // for will never arrive.  Stop waiting for it.
@@ -383,7 +384,8 @@
             }
         } else {
             // Inbound queue has at least one entry.
-            mPendingEvent = mInboundQueue.dequeueAtHead();
+            mPendingEvent = mInboundQueue.front();
+            mInboundQueue.pop_front();
             traceInboundQueueLengthLocked();
         }
 
@@ -483,8 +485,8 @@
 }
 
 bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
-    bool needWake = mInboundQueue.isEmpty();
-    mInboundQueue.enqueueAtTail(entry);
+    bool needWake = mInboundQueue.empty();
+    mInboundQueue.push_back(entry);
     traceInboundQueueLengthLocked();
 
     switch (entry->type) {
@@ -544,9 +546,10 @@
 
 void InputDispatcher::addRecentEventLocked(EventEntry* entry) {
     entry->refCount += 1;
-    mRecentQueue.enqueueAtTail(entry);
-    if (mRecentQueue.count() > RECENT_QUEUE_MAX_SIZE) {
-        mRecentQueue.dequeueAtHead()->release();
+    mRecentQueue.push_back(entry);
+    if (mRecentQueue.size() > RECENT_QUEUE_MAX_SIZE) {
+        mRecentQueue.front()->release();
+        mRecentQueue.pop_front();
     }
 }
 
@@ -703,35 +706,33 @@
 }
 
 bool InputDispatcher::haveCommandsLocked() const {
-    return !mCommandQueue.isEmpty();
+    return !mCommandQueue.empty();
 }
 
 bool InputDispatcher::runCommandsLockedInterruptible() {
-    if (mCommandQueue.isEmpty()) {
+    if (mCommandQueue.empty()) {
         return false;
     }
 
     do {
-        CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
-
+        std::unique_ptr<CommandEntry> commandEntry = std::move(mCommandQueue.front());
+        mCommandQueue.pop_front();
         Command command = commandEntry->command;
-        command(*this, commandEntry); // commands are implicitly 'LockedInterruptible'
+        command(*this, commandEntry.get()); // commands are implicitly 'LockedInterruptible'
 
         commandEntry->connection.clear();
-        delete commandEntry;
-    } while (! mCommandQueue.isEmpty());
+    } while (!mCommandQueue.empty());
     return true;
 }
 
-InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
-    CommandEntry* commandEntry = new CommandEntry(command);
-    mCommandQueue.enqueueAtTail(commandEntry);
-    return commandEntry;
+void InputDispatcher::postCommandLocked(std::unique_ptr<CommandEntry> commandEntry) {
+    mCommandQueue.push_back(std::move(commandEntry));
 }
 
 void InputDispatcher::drainInboundQueueLocked() {
-    while (! mInboundQueue.isEmpty()) {
-        EventEntry* entry = mInboundQueue.dequeueAtHead();
+    while (!mInboundQueue.empty()) {
+        EventEntry* entry = mInboundQueue.front();
+        mInboundQueue.pop_front();
         releaseInboundEventLocked(entry);
     }
     traceInboundQueueLengthLocked();
@@ -809,9 +810,10 @@
     resetKeyRepeatLocked();
 
     // Enqueue a command to run outside the lock to tell the policy that the configuration changed.
-    CommandEntry* commandEntry =
-            postCommandLocked(&InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
+    std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+            &InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
     commandEntry->eventTime = entry->eventTime;
+    postCommandLocked(std::move(commandEntry));
     return true;
 }
 
@@ -883,7 +885,7 @@
     // Give the policy a chance to intercept the key.
     if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
         if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
-            CommandEntry* commandEntry = postCommandLocked(
+            std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
                     &InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
             sp<InputWindowHandle> focusedWindowHandle =
                     getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
@@ -892,6 +894,7 @@
                     getInputChannelLocked(focusedWindowHandle->getToken());
             }
             commandEntry->keyEntry = entry;
+            postCommandLocked(std::move(commandEntry));
             entry->refCount += 1;
             return false; // wait for the command to run
         } else {
@@ -1873,8 +1876,9 @@
     // If the connection is backed up then keep waiting.
     if (connection->inputPublisherBlocked) {
         return StringPrintf("Waiting because the %s window's input channel is full.  "
-                "Outbound queue length: %d.  Wait queue length: %d.",
-                targetType, connection->outboundQueue.count(), connection->waitQueue.count());
+                            "Outbound queue length: %zu.  Wait queue length: %zu.",
+                            targetType, connection->outboundQueue.size(),
+                            connection->waitQueue.size());
     }
 
     // Ensure that the dispatch queues aren't too far backed up for this event.
@@ -1890,11 +1894,13 @@
         // often anticipate pending UI changes when typing on a keyboard.
         // To obtain this behavior, we must serialize key events with respect to all
         // prior input events.
-        if (!connection->outboundQueue.isEmpty() || !connection->waitQueue.isEmpty()) {
+        if (!connection->outboundQueue.empty() || !connection->waitQueue.empty()) {
             return StringPrintf("Waiting to send key event because the %s window has not "
-                    "finished processing all of the input events that were previously "
-                    "delivered to it.  Outbound queue length: %d.  Wait queue length: %d.",
-                    targetType, connection->outboundQueue.count(), connection->waitQueue.count());
+                                "finished processing all of the input events that were previously "
+                                "delivered to it.  Outbound queue length: %zu.  Wait queue length: "
+                                "%zu.",
+                                targetType, connection->outboundQueue.size(),
+                                connection->waitQueue.size());
         }
     } else {
         // Touch events can always be sent to a window immediately because the user intended
@@ -1912,15 +1918,18 @@
         // The one case where we pause input event delivery is when the wait queue is piling
         // up with lots of events because the application is not responding.
         // This condition ensures that ANRs are detected reliably.
-        if (!connection->waitQueue.isEmpty()
-                && currentTime >= connection->waitQueue.head->deliveryTime
-                        + STREAM_AHEAD_EVENT_TIMEOUT) {
+        if (!connection->waitQueue.empty() &&
+            currentTime >=
+                    connection->waitQueue.front()->deliveryTime + STREAM_AHEAD_EVENT_TIMEOUT) {
             return StringPrintf("Waiting to send non-key event because the %s window has not "
-                    "finished processing certain input events that were delivered to it over "
-                    "%0.1fms ago.  Wait queue length: %d.  Wait queue head age: %0.1fms.",
-                    targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f,
-                    connection->waitQueue.count(),
-                    (currentTime - connection->waitQueue.head->deliveryTime) * 0.000001f);
+                                "finished processing certain input events that were delivered to "
+                                "it over "
+                                "%0.1fms ago.  Wait queue length: %zu.  Wait queue head age: "
+                                "%0.1fms.",
+                                targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f,
+                                connection->waitQueue.size(),
+                                (currentTime - connection->waitQueue.front()->deliveryTime) *
+                                        0.000001f);
         }
     }
     return "";
@@ -1982,10 +1991,11 @@
     }
     }
 
-    CommandEntry* commandEntry =
-            postCommandLocked(&InputDispatcher::doPokeUserActivityLockedInterruptible);
+    std::unique_ptr<CommandEntry> commandEntry =
+            std::make_unique<CommandEntry>(&InputDispatcher::doPokeUserActivityLockedInterruptible);
     commandEntry->eventTime = eventEntry->eventTime;
     commandEntry->userActivityEventType = eventType;
+    postCommandLocked(std::move(commandEntry));
 }
 
 void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
@@ -2053,7 +2063,7 @@
         ATRACE_NAME(message.c_str());
     }
 
-    bool wasEmpty = connection->outboundQueue.isEmpty();
+    bool wasEmpty = connection->outboundQueue.empty();
 
     // Enqueue dispatch entries for the requested modes.
     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
@@ -2070,7 +2080,7 @@
             InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
 
     // If the outbound queue was previously empty, start the dispatch cycle going.
-    if (wasEmpty && !connection->outboundQueue.isEmpty()) {
+    if (wasEmpty && !connection->outboundQueue.empty()) {
         startDispatchCycleLocked(currentTime, connection);
     }
 }
@@ -2173,7 +2183,7 @@
     }
 
     // Enqueue the dispatch entry.
-    connection->outboundQueue.enqueueAtTail(dispatchEntry);
+    connection->outboundQueue.push_back(dispatchEntry);
     traceOutboundQueueLength(connection);
 
 }
@@ -2200,9 +2210,10 @@
         return;
     }
 
-    CommandEntry* commandEntry =
-            postCommandLocked(&InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
+    std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+            &InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
     commandEntry->newToken = newToken;
+    postCommandLocked(std::move(commandEntry));
 }
 
 void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -2217,9 +2228,8 @@
             connection->getInputChannelName().c_str());
 #endif
 
-    while (connection->status == Connection::STATUS_NORMAL
-            && !connection->outboundQueue.isEmpty()) {
-        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
+    while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
+        DispatchEntry* dispatchEntry = connection->outboundQueue.front();
         dispatchEntry->deliveryTime = currentTime;
 
         // Publish the event.
@@ -2301,7 +2311,7 @@
         // Check the result.
         if (status) {
             if (status == WOULD_BLOCK) {
-                if (connection->waitQueue.isEmpty()) {
+                if (connection->waitQueue.empty()) {
                     ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
                             "This is unexpected because the wait queue is empty, so the pipe "
                             "should be empty and we shouldn't have any problems writing an "
@@ -2327,9 +2337,11 @@
         }
 
         // Re-enqueue the event on the wait queue.
-        connection->outboundQueue.dequeue(dispatchEntry);
+        connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
+                                                    connection->outboundQueue.end(),
+                                                    dispatchEntry));
         traceOutboundQueueLength(connection);
-        connection->waitQueue.enqueueAtTail(dispatchEntry);
+        connection->waitQueue.push_back(dispatchEntry);
         traceWaitQueueLength(connection);
     }
 }
@@ -2360,9 +2372,9 @@
 #endif
 
     // Clear the dispatch queues.
-    drainDispatchQueue(&connection->outboundQueue);
+    drainDispatchQueue(connection->outboundQueue);
     traceOutboundQueueLength(connection);
-    drainDispatchQueue(&connection->waitQueue);
+    drainDispatchQueue(connection->waitQueue);
     traceWaitQueueLength(connection);
 
     // The connection appears to be unrecoverably broken.
@@ -2377,9 +2389,10 @@
     }
 }
 
-void InputDispatcher::drainDispatchQueue(Queue<DispatchEntry>* queue) {
-    while (!queue->isEmpty()) {
-        DispatchEntry* dispatchEntry = queue->dequeueAtHead();
+void InputDispatcher::drainDispatchQueue(std::deque<DispatchEntry*>& queue) {
+    while (!queue.empty()) {
+        DispatchEntry* dispatchEntry = queue.front();
+        queue.pop_front();
         releaseDispatchEntry(dispatchEntry);
     }
 }
@@ -2907,8 +2920,7 @@
         policyFlags |= POLICY_FLAG_TRUSTED;
     }
 
-    EventEntry* firstInjectedEntry;
-    EventEntry* lastInjectedEntry;
+    std::queue<EventEntry*> injectedEntries;
     switch (event->getType()) {
     case AINPUT_EVENT_TYPE_KEY: {
         KeyEvent keyEvent;
@@ -2941,12 +2953,13 @@
         }
 
         mLock.lock();
-        firstInjectedEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(),
-                keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(),
-                policyFlags, action, flags,
-                keyEvent.getKeyCode(), keyEvent.getScanCode(), keyEvent.getMetaState(),
-                keyEvent.getRepeatCount(), keyEvent.getDownTime());
-        lastInjectedEntry = firstInjectedEntry;
+        KeyEntry* injectedEntry =
+                new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(),
+                             keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(),
+                             policyFlags, action, flags, keyEvent.getKeyCode(),
+                             keyEvent.getScanCode(), keyEvent.getMetaState(),
+                             keyEvent.getRepeatCount(), keyEvent.getDownTime());
+        injectedEntries.push(injectedEntry);
         break;
     }
 
@@ -2974,7 +2987,7 @@
         mLock.lock();
         const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
         const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
-        firstInjectedEntry =
+        MotionEntry* injectedEntry =
                 new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
                                 motionEvent->getDeviceId(), motionEvent->getSource(),
                                 motionEvent->getDisplayId(), policyFlags, action, actionButton,
@@ -2985,7 +2998,7 @@
                                 motionEvent->getRawYCursorPosition(), motionEvent->getDownTime(),
                                 uint32_t(pointerCount), pointerProperties, samplePointerCoords,
                                 motionEvent->getXOffset(), motionEvent->getYOffset());
-        lastInjectedEntry = firstInjectedEntry;
+        injectedEntries.push(injectedEntry);
         for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
             sampleEventTimes += 1;
             samplePointerCoords += pointerCount;
@@ -3002,8 +3015,7 @@
                                     motionEvent->getDownTime(), uint32_t(pointerCount),
                                     pointerProperties, samplePointerCoords,
                                     motionEvent->getXOffset(), motionEvent->getYOffset());
-            lastInjectedEntry->next = nextInjectedEntry;
-            lastInjectedEntry = nextInjectedEntry;
+            injectedEntries.push(nextInjectedEntry);
         }
         break;
     }
@@ -3019,13 +3031,12 @@
     }
 
     injectionState->refCount += 1;
-    lastInjectedEntry->injectionState = injectionState;
+    injectedEntries.back()->injectionState = injectionState;
 
     bool needWake = false;
-    for (EventEntry* entry = firstInjectedEntry; entry != nullptr; ) {
-        EventEntry* nextEntry = entry->next;
-        needWake |= enqueueInboundEventLocked(entry);
-        entry = nextEntry;
+    while (!injectedEntries.empty()) {
+        needWake |= enqueueInboundEventLocked(injectedEntries.front());
+        injectedEntries.pop();
     }
 
     mLock.unlock();
@@ -3756,9 +3767,9 @@
     nsecs_t currentTime = now();
 
     // Dump recently dispatched or dropped events from oldest to newest.
-    if (!mRecentQueue.isEmpty()) {
-        dump += StringPrintf(INDENT "RecentQueue: length=%u\n", mRecentQueue.count());
-        for (EventEntry* entry = mRecentQueue.head; entry; entry = entry->next) {
+    if (!mRecentQueue.empty()) {
+        dump += StringPrintf(INDENT "RecentQueue: length=%zu\n", mRecentQueue.size());
+        for (EventEntry* entry : mRecentQueue) {
             dump += INDENT2;
             entry->appendDescription(dump);
             dump += StringPrintf(", age=%0.1fms\n",
@@ -3780,9 +3791,9 @@
     }
 
     // Dump inbound events from oldest to newest.
-    if (!mInboundQueue.isEmpty()) {
-        dump += StringPrintf(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
-        for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) {
+    if (!mInboundQueue.empty()) {
+        dump += StringPrintf(INDENT "InboundQueue: length=%zu\n", mInboundQueue.size());
+        for (EventEntry* entry : mInboundQueue) {
             dump += INDENT2;
             entry->appendDescription(dump);
             dump += StringPrintf(", age=%0.1fms\n",
@@ -3815,11 +3826,10 @@
                     connection->getStatusLabel(), toString(connection->monitor),
                     toString(connection->inputPublisherBlocked));
 
-            if (!connection->outboundQueue.isEmpty()) {
-                dump += StringPrintf(INDENT3 "OutboundQueue: length=%u\n",
-                        connection->outboundQueue.count());
-                for (DispatchEntry* entry = connection->outboundQueue.head; entry;
-                        entry = entry->next) {
+            if (!connection->outboundQueue.empty()) {
+                dump += StringPrintf(INDENT3 "OutboundQueue: length=%zu\n",
+                                     connection->outboundQueue.size());
+                for (DispatchEntry* entry : connection->outboundQueue) {
                     dump.append(INDENT4);
                     entry->eventEntry->appendDescription(dump);
                     dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n",
@@ -3830,11 +3840,10 @@
                 dump += INDENT3 "OutboundQueue: <empty>\n";
             }
 
-            if (!connection->waitQueue.isEmpty()) {
-                dump += StringPrintf(INDENT3 "WaitQueue: length=%u\n",
-                        connection->waitQueue.count());
-                for (DispatchEntry* entry = connection->waitQueue.head; entry;
-                        entry = entry->next) {
+            if (!connection->waitQueue.empty()) {
+                dump += StringPrintf(INDENT3 "WaitQueue: length=%zu\n",
+                                     connection->waitQueue.size());
+                for (DispatchEntry* entry : connection->waitQueue) {
                     dump += INDENT4;
                     entry->eventEntry->appendDescription(dump);
                     dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, "
@@ -4087,12 +4096,13 @@
 
 void InputDispatcher::onDispatchCycleFinishedLocked(
         nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
-    CommandEntry* commandEntry =
-            postCommandLocked(&InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
+    std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+            &InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
     commandEntry->connection = connection;
     commandEntry->eventTime = currentTime;
     commandEntry->seq = seq;
     commandEntry->handled = handled;
+    postCommandLocked(std::move(commandEntry));
 }
 
 void InputDispatcher::onDispatchCycleBrokenLocked(
@@ -4100,19 +4110,21 @@
     ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
             connection->getInputChannelName().c_str());
 
-    CommandEntry* commandEntry =
-            postCommandLocked(&InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
+    std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+            &InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
     commandEntry->connection = connection;
+    postCommandLocked(std::move(commandEntry));
 }
 
 void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
         const sp<InputWindowHandle>& newFocus) {
     sp<IBinder> oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr;
     sp<IBinder> newToken = newFocus != nullptr ? newFocus->getToken() : nullptr;
-    CommandEntry* commandEntry =
-            postCommandLocked(&InputDispatcher::doNotifyFocusChangedLockedInterruptible);
+    std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+            &InputDispatcher::doNotifyFocusChangedLockedInterruptible);
     commandEntry->oldToken = oldToken;
     commandEntry->newToken = newToken;
+    postCommandLocked(std::move(commandEntry));
 }
 
 void InputDispatcher::onANRLocked(
@@ -4142,12 +4154,13 @@
     mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason);
     dumpDispatchStateLocked(mLastANRState);
 
-    CommandEntry* commandEntry =
-            postCommandLocked(&InputDispatcher::doNotifyANRLockedInterruptible);
+    std::unique_ptr<CommandEntry> commandEntry =
+            std::make_unique<CommandEntry>(&InputDispatcher::doNotifyANRLockedInterruptible);
     commandEntry->inputApplicationHandle = applicationHandle;
     commandEntry->inputChannel = windowHandle != nullptr ?
             getInputChannelLocked(windowHandle->getToken()) : nullptr;
     commandEntry->reason = reason;
+    postCommandLocked(std::move(commandEntry));
 }
 
 void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible (
@@ -4242,10 +4255,12 @@
     const bool handled = commandEntry->handled;
 
     // Handle post-event policy actions.
-    DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);
-    if (!dispatchEntry) {
+    std::deque<InputDispatcher::DispatchEntry*>::iterator dispatchEntryIt =
+            connection->findWaitQueueEntry(seq);
+    if (dispatchEntryIt == connection->waitQueue.end()) {
         return;
     }
+    DispatchEntry* dispatchEntry = *dispatchEntryIt;
 
     nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
     if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
@@ -4273,11 +4288,13 @@
     // Note that because the lock might have been released, it is possible that the
     // contents of the wait queue to have been drained, so we need to double-check
     // a few things.
-    if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
-        connection->waitQueue.dequeue(dispatchEntry);
+    dispatchEntryIt = connection->findWaitQueueEntry(seq);
+    if (dispatchEntryIt != connection->waitQueue.end()) {
+        dispatchEntry = *dispatchEntryIt;
+        connection->waitQueue.erase(dispatchEntryIt);
         traceWaitQueueLength(connection);
         if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
-            connection->outboundQueue.enqueueAtHead(dispatchEntry);
+            connection->outboundQueue.push_front(dispatchEntry);
             traceOutboundQueueLength(connection);
         } else {
             releaseDispatchEntry(dispatchEntry);
@@ -4496,7 +4513,7 @@
 
 void InputDispatcher::traceInboundQueueLengthLocked() {
     if (ATRACE_ENABLED()) {
-        ATRACE_INT("iq", mInboundQueue.count());
+        ATRACE_INT("iq", mInboundQueue.size());
     }
 }
 
@@ -4504,7 +4521,7 @@
     if (ATRACE_ENABLED()) {
         char counterName[40];
         snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName().c_str());
-        ATRACE_INT(counterName, connection->outboundQueue.count());
+        ATRACE_INT(counterName, connection->outboundQueue.size());
     }
 }
 
@@ -4512,7 +4529,7 @@
     if (ATRACE_ENABLED()) {
         char counterName[40];
         snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName().c_str());
-        ATRACE_INT(counterName, connection->waitQueue.count());
+        ATRACE_INT(counterName, connection->waitQueue.size());
     }
 }
 
@@ -5148,13 +5165,14 @@
     }
 }
 
-InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) {
-    for (DispatchEntry* entry = waitQueue.head; entry != nullptr; entry = entry->next) {
-        if (entry->seq == seq) {
-            return entry;
+std::deque<InputDispatcher::DispatchEntry*>::iterator
+InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) {
+    for (std::deque<DispatchEntry*>::iterator it = waitQueue.begin(); it != waitQueue.end(); it++) {
+        if ((*it)->seq == seq) {
+            return it;
         }
     }
-    return nullptr;
+    return waitQueue.end();
 }
 
 // --- InputDispatcher::Monitor
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 147437c..92e1e5f 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -33,9 +33,10 @@
 #include <cutils/atomic.h>
 #include <unordered_map>
 
+#include <limits.h>
 #include <stddef.h>
 #include <unistd.h>
-#include <limits.h>
+#include <deque>
 #include <unordered_map>
 
 #include "InputListener.h"
@@ -450,14 +451,6 @@
     virtual status_t pilferPointers(const sp<IBinder>& token) override;
 
 private:
-    template <typename T>
-    struct Link {
-        T* next;
-        T* prev;
-
-    protected:
-        inline Link() : next(nullptr), prev(nullptr) { }
-    };
 
     struct InjectionState {
         mutable int32_t refCount;
@@ -475,7 +468,7 @@
         ~InjectionState();
     };
 
-    struct EventEntry : Link<EventEntry> {
+    struct EventEntry {
         enum {
             TYPE_CONFIGURATION_CHANGED,
             TYPE_DEVICE_RESET,
@@ -592,7 +585,7 @@
     };
 
     // Tracks the progress of dispatching a particular event to a particular connection.
-    struct DispatchEntry : Link<DispatchEntry> {
+    struct DispatchEntry {
         const uint32_t seq; // unique sequence number, never 0
 
         EventEntry* eventEntry; // the event to dispatch
@@ -647,7 +640,7 @@
     typedef std::function<void(InputDispatcher&, CommandEntry*)> Command;
 
     class Connection;
-    struct CommandEntry : Link<CommandEntry> {
+    struct CommandEntry {
         explicit CommandEntry(Command command);
         ~CommandEntry();
 
@@ -667,75 +660,6 @@
         sp<IBinder> newToken;
     };
 
-    // Generic queue implementation.
-    template <typename T>
-    struct Queue {
-        T* head;
-        T* tail;
-        uint32_t entryCount;
-
-        inline Queue() : head(nullptr), tail(nullptr), entryCount(0) {
-        }
-
-        inline bool isEmpty() const {
-            return !head;
-        }
-
-        inline void enqueueAtTail(T* entry) {
-            entryCount++;
-            entry->prev = tail;
-            if (tail) {
-                tail->next = entry;
-            } else {
-                head = entry;
-            }
-            entry->next = nullptr;
-            tail = entry;
-        }
-
-        inline void enqueueAtHead(T* entry) {
-            entryCount++;
-            entry->next = head;
-            if (head) {
-                head->prev = entry;
-            } else {
-                tail = entry;
-            }
-            entry->prev = nullptr;
-            head = entry;
-        }
-
-        inline void dequeue(T* entry) {
-            entryCount--;
-            if (entry->prev) {
-                entry->prev->next = entry->next;
-            } else {
-                head = entry->next;
-            }
-            if (entry->next) {
-                entry->next->prev = entry->prev;
-            } else {
-                tail = entry->prev;
-            }
-        }
-
-        inline T* dequeueAtHead() {
-            entryCount--;
-            T* entry = head;
-            head = entry->next;
-            if (head) {
-                head->prev = nullptr;
-            } else {
-                tail = nullptr;
-            }
-            return entry;
-        }
-
-        uint32_t count() const {
-            return entryCount;
-        }
-    };
-
     /* Specifies which events are to be canceled and why. */
     struct CancelationOptions {
         enum Mode {
@@ -886,11 +810,11 @@
         bool inputPublisherBlocked;
 
         // Queue of events that need to be published to the connection.
-        Queue<DispatchEntry> outboundQueue;
+        std::deque<DispatchEntry*> outboundQueue;
 
         // Queue of events that have been published to the connection but that have not
         // yet received a "finished" response from the application.
-        Queue<DispatchEntry> waitQueue;
+        std::deque<DispatchEntry*> waitQueue;
 
         explicit Connection(const sp<InputChannel>& inputChannel, bool monitor);
 
@@ -899,7 +823,7 @@
         const std::string getWindowName() const;
         const char* getStatusLabel() const;
 
-        DispatchEntry* findWaitQueueEntry(uint32_t seq);
+        std::deque<DispatchEntry*>::iterator findWaitQueueEntry(uint32_t seq);
     };
 
     struct Monitor {
@@ -927,9 +851,9 @@
     sp<Looper> mLooper;
 
     EventEntry* mPendingEvent GUARDED_BY(mLock);
-    Queue<EventEntry> mInboundQueue GUARDED_BY(mLock);
-    Queue<EventEntry> mRecentQueue GUARDED_BY(mLock);
-    Queue<CommandEntry> mCommandQueue GUARDED_BY(mLock);
+    std::deque<EventEntry*> mInboundQueue GUARDED_BY(mLock);
+    std::deque<EventEntry*> mRecentQueue GUARDED_BY(mLock);
+    std::deque<std::unique_ptr<CommandEntry>> mCommandQueue GUARDED_BY(mLock);
 
     DropReason mLastDropReason GUARDED_BY(mLock);
 
@@ -1029,7 +953,7 @@
     // Deferred command processing.
     bool haveCommandsLocked() const REQUIRES(mLock);
     bool runCommandsLockedInterruptible() REQUIRES(mLock);
-    CommandEntry* postCommandLocked(Command command) REQUIRES(mLock);
+    void postCommandLocked(std::unique_ptr<CommandEntry> commandEntry) REQUIRES(mLock);
 
     // Input filter processing.
     bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock);
@@ -1221,7 +1145,7 @@
             uint32_t seq, bool handled) REQUIRES(mLock);
     void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
             bool notify) REQUIRES(mLock);
-    void drainDispatchQueue(Queue<DispatchEntry>* queue);
+    void drainDispatchQueue(std::deque<DispatchEntry*>& queue);
     void releaseDispatchEntry(DispatchEntry* dispatchEntry);
     static int handleReceiveCallback(int fd, int events, void* data);
     // The action sent should only be of type AMOTION_EVENT_*
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 965d8f4..afb9cec 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -138,7 +138,6 @@
         "Layer.cpp",
         "LayerProtoHelper.cpp",
         "LayerRejecter.cpp",
-        "LayerStats.cpp",
         "LayerVector.cpp",
         "MonitoredProducer.cpp",
         "NativeWindowSurface.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 87bec11..13c748f 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -167,7 +167,7 @@
         }
         return std::nullopt;
     }
-    bool blackOutLayer = (isProtected() && !targetSettings.supportProtectedContent) ||
+    bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
             (isSecure() && !targetSettings.isSecure);
     const State& s(getDrawingState());
     auto& layer = *result;
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index c86acf0..7a0f82b 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -48,7 +48,7 @@
 class BufferLayer : public Layer {
 public:
     explicit BufferLayer(const LayerCreationArgs& args);
-    ~BufferLayer() override;
+    virtual ~BufferLayer() override;
 
     // -----------------------------------------------------------------------
     // Overriden from Layer
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 0f26211..611decf 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -51,6 +51,16 @@
     mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
 }
 
+BufferStateLayer::~BufferStateLayer() {
+    if (mActiveBuffer != nullptr) {
+        // Ensure that mActiveBuffer is uncached from RenderEngine here, as
+        // RenderEngine may have been using the buffer as an external texture
+        // after the client uncached the buffer.
+        auto& engine(mFlinger->getRenderEngine());
+        engine.unbindExternalTextureBuffer(mActiveBuffer->getId());
+    }
+}
+
 // -----------------------------------------------------------------------
 // Interface implementation for Layer
 // -----------------------------------------------------------------------
@@ -604,10 +614,6 @@
     }
 }
 
-void BufferStateLayer::bufferErased(const client_cache_t& clientCacheId) {
-    mFlinger->getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id);
-}
-
 void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) {
     std::lock_guard lock(mMutex);
     if (!clientCacheId.isValid()) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 5e5b9b0..6db91ef 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -35,6 +35,8 @@
 public:
     explicit BufferStateLayer(const LayerCreationArgs&);
 
+    ~BufferStateLayer() override;
+
     // -----------------------------------------------------------------------
     // Interface implementation for Layer
     // -----------------------------------------------------------------------
@@ -102,9 +104,6 @@
     bool fenceHasSignaled() const override;
     bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
 
-    // Inherit from ClientCache::ErasedRecipient
-    void bufferErased(const client_cache_t& clientCacheId) override;
-
 private:
     nsecs_t getDesiredPresentTime() override;
     std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index 77f2f57..16fe27c 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -55,16 +55,16 @@
     return true;
 }
 
-void ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
+bool ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
     auto& [processToken, id] = cacheId;
     if (processToken == nullptr) {
         ALOGE("failed to cache buffer: invalid process token");
-        return;
+        return false;
     }
 
     if (!buffer) {
         ALOGE("failed to cache buffer: invalid buffer");
-        return;
+        return false;
     }
 
     std::lock_guard lock(mMutex);
@@ -77,13 +77,13 @@
         token = processToken.promote();
         if (!token) {
             ALOGE("failed to cache buffer: invalid token");
-            return;
+            return false;
         }
 
         status_t err = token->linkToDeath(mDeathRecipient);
         if (err != NO_ERROR) {
             ALOGE("failed to cache buffer: could not link to death");
-            return;
+            return false;
         }
         auto [itr, success] =
                 mBuffers.emplace(processToken, std::unordered_map<uint64_t, ClientCacheBuffer>());
@@ -95,10 +95,11 @@
 
     if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
         ALOGE("failed to cache buffer: cache is full");
-        return;
+        return false;
     }
 
     processBuffers[id].buffer = buffer;
+    return true;
 }
 
 void ClientCache::erase(const client_cache_t& cacheId) {
@@ -139,16 +140,17 @@
     return buf->buffer;
 }
 
-void ClientCache::registerErasedRecipient(const client_cache_t& cacheId,
+bool ClientCache::registerErasedRecipient(const client_cache_t& cacheId,
                                           const wp<ErasedRecipient>& recipient) {
     std::lock_guard lock(mMutex);
 
     ClientCacheBuffer* buf = nullptr;
     if (!getBuffer(cacheId, &buf)) {
         ALOGE("failed to register erased recipient, could not retrieve buffer");
-        return;
+        return false;
     }
     buf->recipients.insert(recipient);
+    return true;
 }
 
 void ClientCache::unregisterErasedRecipient(const client_cache_t& cacheId,
diff --git a/services/surfaceflinger/ClientCache.h b/services/surfaceflinger/ClientCache.h
index 9f057c4..aa6c80d 100644
--- a/services/surfaceflinger/ClientCache.h
+++ b/services/surfaceflinger/ClientCache.h
@@ -36,7 +36,7 @@
 public:
     ClientCache();
 
-    void add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer);
+    bool add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer);
     void erase(const client_cache_t& cacheId);
 
     sp<GraphicBuffer> get(const client_cache_t& cacheId);
@@ -48,7 +48,7 @@
         virtual void bufferErased(const client_cache_t& clientCacheId) = 0;
     };
 
-    void registerErasedRecipient(const client_cache_t& cacheId,
+    bool registerErasedRecipient(const client_cache_t& cacheId,
                                  const wp<ErasedRecipient>& recipient);
     void unregisterErasedRecipient(const client_cache_t& cacheId,
                                    const wp<ErasedRecipient>& recipient);
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 6f076ad..ae6bdbc 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -94,6 +94,7 @@
         "tests/LayerTest.cpp",
         "tests/MockHWC2.cpp",
         "tests/MockHWComposer.cpp",
+        "tests/MockPowerAdvisor.cpp",
         "tests/OutputTest.cpp",
         "tests/OutputLayerTest.cpp",
         "tests/RenderSurfaceTest.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
index 0b6b4e4..0778936 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -20,6 +20,7 @@
 #include <optional>
 
 #include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/PowerAdvisor.h"
 
 namespace android::compositionengine {
 
@@ -37,6 +38,10 @@
 
     // Identifies the display to the HWC, if composition is supported by it
     std::optional<DisplayId> displayId;
+
+    // Optional pointer to the power advisor interface, if one is needed for
+    // this display.
+    Hwc2::PowerAdvisor* powerAdvisor = nullptr;
 };
 
 /**
@@ -68,6 +73,10 @@
         mArgs.displayId = displayId;
         return *this;
     }
+    DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
+        mArgs.powerAdvisor = powerAdvisor;
+        return *this;
+    }
 
 private:
     DisplayCreationArgs mArgs;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 94fab1f..2a901ae 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -59,7 +59,7 @@
         const bool isSecure;
 
         // If set to true, the target buffer has protected content support.
-        const bool supportProtectedContent;
+        const bool supportsProtectedContent;
 
         // Modified by each call to prepareClientComposition to indicate the
         // region of the target buffer that should be cleared.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index d96d58c..d5763d5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -116,6 +116,12 @@
     // The color transform
     mat4 colorTransform;
     bool colorTransformIsIdentity{true};
+
+    // True if the layer is completely opaque
+    bool isOpaque{true};
+
+    // True if the layer has protected content
+    bool hasProtectedContent{false};
 };
 
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 4dfcfa4..f73304d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -22,6 +22,7 @@
 #include <unordered_map>
 
 #include <math/mat4.h>
+#include <renderengine/LayerSettings.h>
 #include <ui/Fence.h>
 #include <ui/GraphicTypes.h>
 #include <ui/Region.h>
@@ -156,6 +157,12 @@
     // Prepares a frame for display
     virtual void prepareFrame() = 0;
 
+    // Performs client composition as needed for layers on the output. The
+    // output fence is set to a fence to signal when client composition is
+    // finished.
+    // Returns false if client composition cannot be performed.
+    virtual bool composeSurfaces(const Region& debugFence, base::unique_fd* outReadyFence) = 0;
+
     // Posts the new frame, and sets release fences.
     virtual void postFramebuffer() = 0;
 
@@ -163,7 +170,14 @@
     virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
     virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
     virtual void chooseCompositionStrategy() = 0;
+    virtual bool getSkipColorTransform() const = 0;
     virtual FrameFences presentAndGetFrameFences() = 0;
+    virtual std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+            bool supportsProtectedContent, Region& clearRegion) = 0;
+    virtual void appendRegionFlashRequests(
+            const Region& flashRegion,
+            std::vector<renderengine::LayerSettings>& clientCompositionLayers) = 0;
+    virtual void setExpensiveRenderingExpected(bool enabled) = 0;
 };
 
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index d7f00a9..5f62b32c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -93,6 +93,9 @@
     // Applies a HWC device layer request
     virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0;
 
+    // Returns true if the composition settings scale pixels
+    virtual bool needsFiltering() const = 0;
+
     // Debugging
     virtual void dump(std::string& result) const = 0;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 795061a..36e4aac 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -23,6 +23,7 @@
 
 #include "DisplayHardware/DisplayIdentification.h"
 #include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
 
 namespace android::compositionengine {
 
@@ -42,7 +43,9 @@
     void setColorTransform(const mat4&) override;
     void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
     void chooseCompositionStrategy() override;
+    bool getSkipColorTransform() const override;
     compositionengine::Output::FrameFences presentAndGetFrameFences() override;
+    void setExpensiveRenderingExpected(bool) override;
 
     // compositionengine::Display overrides
     const std::optional<DisplayId>& getId() const override;
@@ -65,9 +68,11 @@
 private:
     const bool mIsVirtual;
     std::optional<DisplayId> mId;
+    Hwc2::PowerAdvisor* const mPowerAdvisor{nullptr};
 };
 
 std::shared_ptr<Display> createDisplay(const compositionengine::CompositionEngine&,
                                        compositionengine::DisplayCreationArgs&&);
+
 } // namespace impl
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 5f4a764..3972f2b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -77,6 +77,7 @@
 
     void beginFrame() override;
     void prepareFrame() override;
+    bool composeSurfaces(const Region&, base::unique_fd*) override;
     void postFramebuffer() override;
 
     // Testing
@@ -86,7 +87,13 @@
 protected:
     const CompositionEngine& getCompositionEngine() const;
     void chooseCompositionStrategy() override;
+    bool getSkipColorTransform() const override;
     compositionengine::Output::FrameFences presentAndGetFrameFences() override;
+    std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+            bool supportsProtectedContent, Region& clearRegion) override;
+    void appendRegionFlashRequests(const Region&,
+                                   std::vector<renderengine::LayerSettings>&) override;
+    void setExpensiveRenderingExpected(bool enabled) override;
     void dumpBase(std::string&) const;
 
 private:
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index d8ad02a..4c3f935 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -55,6 +55,7 @@
     void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override;
     void prepareForDeviceLayerRequests() override;
     void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override;
+    bool needsFiltering() const override;
 
     void dump(std::string& result) const override;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index d494413..c944bec 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -77,8 +77,17 @@
     MOCK_METHOD0(prepareFrame, void());
     MOCK_METHOD0(chooseCompositionStrategy, void());
 
+    MOCK_METHOD2(composeSurfaces, bool(const Region&, base::unique_fd*));
+    MOCK_CONST_METHOD0(getSkipColorTransform, bool());
+
     MOCK_METHOD0(postFramebuffer, void());
     MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences());
+
+    MOCK_METHOD2(generateClientCompositionRequests,
+                 std::vector<renderengine::LayerSettings>(bool, Region&));
+    MOCK_METHOD2(appendRegionFlashRequests,
+                 void(const Region&, std::vector<renderengine::LayerSettings>&));
+    MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
 };
 
 } // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 195648f..d8d637d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -46,6 +46,7 @@
     MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition));
     MOCK_METHOD0(prepareForDeviceLayerRequests, void());
     MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request));
+    MOCK_CONST_METHOD0(needsFiltering, bool());
 
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 6831901..6cd392e 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -26,6 +26,7 @@
 #include <utils/Trace.h>
 
 #include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
 
 namespace android::compositionengine::impl {
 
@@ -38,7 +39,8 @@
 Display::Display(const CompositionEngine& compositionEngine, DisplayCreationArgs&& args)
       : compositionengine::impl::Output(compositionEngine),
         mIsVirtual(args.isVirtual),
-        mId(args.displayId) {
+        mId(args.displayId),
+        mPowerAdvisor(args.powerAdvisor) {
     editState().isSecure = args.isSecure;
 }
 
@@ -160,6 +162,15 @@
     state.usesDeviceComposition = !allLayersRequireClientComposition();
 }
 
+bool Display::getSkipColorTransform() const {
+    if (!mId) {
+        return false;
+    }
+
+    auto& hwc = getCompositionEngine().getHwComposer();
+    return hwc.hasDisplayCapability(*mId, HWC2::DisplayCapability::SkipClientColorTransform);
+}
+
 bool Display::anyLayersRequireClientComposition() const {
     const auto& layers = getOutputLayersOrderedByZ();
     return std::any_of(layers.cbegin(), layers.cend(),
@@ -240,4 +251,12 @@
     return result;
 }
 
+void Display::setExpensiveRenderingExpected(bool enabled) {
+    Output::setExpensiveRenderingExpected(enabled);
+
+    if (mPowerAdvisor && mId) {
+        mPowerAdvisor->setExpensiveRenderingExpected(*mId, enabled);
+    }
+}
+
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
index 37d6eaa..0dc4bf1 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
@@ -71,6 +71,8 @@
     dumpVal(out, "color", state.color);
 
     out.append("\n      ");
+    dumpVal(out, "isOpaque", state.isOpaque);
+    dumpVal(out, "hasProtectedContent", state.hasProtectedContent);
     dumpVal(out, "isColorspaceAgnostic", state.isColorspaceAgnostic);
     dumpVal(out, "dataspace", toString(state.dataspace), state.dataspace);
     dumpVal(out, "hdr metadata types", state.hdrMetadata.validTypes);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index b411e0a..fb576e0 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -17,13 +17,20 @@
 #include <android-base/stringprintf.h>
 #include <compositionengine/CompositionEngine.h>
 #include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/Layer.h>
 #include <compositionengine/LayerFE.h>
 #include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/LayerCompositionState.h>
 #include <compositionengine/impl/Output.h>
 #include <compositionengine/impl/OutputLayer.h>
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/RenderEngine.h>
 #include <ui/DebugUtils.h>
+#include <ui/HdrCapabilities.h>
 #include <utils/Trace.h>
 
+#include "TracedOrdinal.h"
+
 namespace android::compositionengine {
 
 Output::~Output() = default;
@@ -73,10 +80,10 @@
     dirtyEntireOutput();
 }
 
-// TODO(lpique): Rename setSize() once more is moved.
+// TODO(b/121291683): Rename setSize() once more is moved.
 void Output::setBounds(const ui::Size& size) {
     mRenderSurface->setDisplaySize(size);
-    // TODO(lpique): Rename mState.size once more is moved.
+    // TODO(b/121291683): Rename mState.size once more is moved.
     mState.bounds = Rect(mRenderSurface->getSize());
 
     dirtyEntireOutput();
@@ -292,6 +299,179 @@
     mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition);
 }
 
+bool Output::composeSurfaces(const Region& debugRegion, base::unique_fd* readyFence) {
+    ATRACE_CALL();
+    ALOGV(__FUNCTION__);
+
+    const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
+                                                      mState.usesClientComposition};
+    if (!hasClientComposition) {
+        return true;
+    }
+
+    ALOGV("hasClientComposition");
+
+    auto& renderEngine = mCompositionEngine.getRenderEngine();
+    const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
+
+    renderengine::DisplaySettings clientCompositionDisplay;
+    clientCompositionDisplay.physicalDisplay = mState.frame;
+    clientCompositionDisplay.clip = mState.scissor;
+    clientCompositionDisplay.globalTransform = mState.transform.asMatrix4();
+    clientCompositionDisplay.orientation = mState.orientation;
+    clientCompositionDisplay.outputDataspace =
+            mDisplayColorProfile->hasWideColorGamut() ? mState.dataspace : ui::Dataspace::UNKNOWN;
+    clientCompositionDisplay.maxLuminance =
+            mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
+
+    // Compute the global color transform matrix.
+    if (!mState.usesDeviceComposition && !getSkipColorTransform()) {
+        clientCompositionDisplay.colorTransform = mState.colorTransformMat;
+    }
+
+    // Note: Updated by generateClientCompositionRequests
+    clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
+
+    // Generate the client composition requests for the layers on this output.
+    std::vector<renderengine::LayerSettings> clientCompositionLayers =
+            generateClientCompositionRequests(supportsProtectedContent,
+                                              clientCompositionDisplay.clearRegion);
+    appendRegionFlashRequests(debugRegion, clientCompositionLayers);
+
+    // If we the display is secure, protected content support is enabled, and at
+    // least one layer has protected content, we need to use a secure back
+    // buffer.
+    if (mState.isSecure && supportsProtectedContent) {
+        bool needsProtected =
+                std::any_of(mOutputLayersOrderedByZ.begin(), mOutputLayersOrderedByZ.end(),
+                            [](auto& layer) {
+                                return layer->getLayer().getState().frontEnd.hasProtectedContent;
+                            });
+        if (needsProtected != renderEngine.isProtected()) {
+            renderEngine.useProtectedContext(needsProtected);
+        }
+        if (needsProtected != mRenderSurface->isProtected() &&
+            needsProtected == renderEngine.isProtected()) {
+            mRenderSurface->setProtected(needsProtected);
+        }
+    }
+
+    base::unique_fd fd;
+    sp<GraphicBuffer> buf = mRenderSurface->dequeueBuffer(&fd);
+    if (buf == nullptr) {
+        ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
+              "client composition for this frame",
+              mName.c_str());
+        return false;
+    }
+
+    // We boost GPU frequency here because there will be color spaces conversion
+    // and it's expensive. We boost the GPU frequency so that GPU composition can
+    // finish in time. We must reset GPU frequency afterwards, because high frequency
+    // consumes extra battery.
+    const bool expensiveRenderingExpected =
+            clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3;
+    if (expensiveRenderingExpected) {
+        setExpensiveRenderingExpected(true);
+    }
+
+    renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
+                            buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
+                            readyFence);
+
+    if (expensiveRenderingExpected) {
+        setExpensiveRenderingExpected(false);
+    }
+
+    return true;
+}
+
+std::vector<renderengine::LayerSettings> Output::generateClientCompositionRequests(
+        bool supportsProtectedContent, Region& clearRegion) {
+    std::vector<renderengine::LayerSettings> clientCompositionLayers;
+    ALOGV("Rendering client layers");
+
+    const Region viewportRegion(mState.viewport);
+    const bool useIdentityTransform = false;
+    bool firstLayer = true;
+    // Used when a layer clears part of the buffer.
+    Region dummyRegion;
+
+    for (auto& layer : mOutputLayersOrderedByZ) {
+        const auto& layerState = layer->getState();
+        const auto& layerFEState = layer->getLayer().getState().frontEnd;
+        auto& layerFE = layer->getLayerFE();
+
+        const Region clip(viewportRegion.intersect(layer->getState().visibleRegion));
+        ALOGV("Layer: %s", layerFE.getDebugName());
+        if (clip.isEmpty()) {
+            ALOGV("  Skipping for empty clip");
+            firstLayer = false;
+            continue;
+        }
+
+        bool clientComposition = layer->requiresClientComposition();
+
+        // We clear the client target for non-client composed layers if
+        // requested by the HWC. We skip this if the layer is not an opaque
+        // rectangle, as by definition the layer must blend with whatever is
+        // underneath. We also skip the first layer as the buffer target is
+        // guaranteed to start out cleared.
+        bool clearClientComposition =
+                layerState.clearClientTarget && layerFEState.isOpaque && !firstLayer;
+
+        ALOGV("  Composition type: client %d clear %d", clientComposition, clearClientComposition);
+
+        if (clientComposition || clearClientComposition) {
+            compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+                    clip,
+                    useIdentityTransform,
+                    layer->needsFiltering() || mState.needsFiltering,
+                    mState.isSecure,
+                    supportsProtectedContent,
+                    clientComposition ? clearRegion : dummyRegion,
+            };
+            if (auto result = layerFE.prepareClientComposition(targetSettings)) {
+                if (clearClientComposition) {
+                    auto& layerSettings = *result;
+                    layerSettings.source.buffer.buffer = nullptr;
+                    layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
+                    layerSettings.alpha = half(0.0);
+                    layerSettings.disableBlending = true;
+                }
+
+                clientCompositionLayers.push_back(*result);
+            }
+        }
+
+        firstLayer = false;
+    }
+
+    return clientCompositionLayers;
+}
+
+void Output::appendRegionFlashRequests(
+        const Region& flashRegion,
+        std::vector<renderengine::LayerSettings>& clientCompositionLayers) {
+    if (flashRegion.isEmpty()) {
+        return;
+    }
+
+    renderengine::LayerSettings layerSettings;
+    layerSettings.source.buffer.buffer = nullptr;
+    layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
+    layerSettings.alpha = half(1.0);
+
+    for (const auto& rect : flashRegion) {
+        layerSettings.geometry.boundaries = rect.toFloatRect();
+        clientCompositionLayers.push_back(layerSettings);
+    }
+}
+
+void Output::setExpensiveRenderingExpected(bool) {
+    // The base class does nothing with this call.
+}
+
 void Output::postFramebuffer() {
     ATRACE_CALL();
     ALOGV(__FUNCTION__);
@@ -300,10 +480,10 @@
         return;
     }
 
-    mRenderSurface->onPresentDisplayCompleted();
-
     auto frame = presentAndGetFrameFences();
 
+    mRenderSurface->onPresentDisplayCompleted();
+
     for (auto& layer : getOutputLayersOrderedByZ()) {
         // The layer buffer from the previous frame (if any) is released
         // by HWC only when the release fence from this frame (if any) is
@@ -353,6 +533,10 @@
     mState.usesDeviceComposition = false;
 }
 
+bool Output::getSkipColorTransform() const {
+    return true;
+}
+
 compositionengine::Output::FrameFences Output::presentAndGetFrameFences() {
     compositionengine::Output::FrameFences result;
     if (mState.usesClientComposition) {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 6e744b9..e721cf5 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -614,6 +614,13 @@
     }
 }
 
+bool OutputLayer::needsFiltering() const {
+    const auto& displayFrame = mState.displayFrame;
+    const auto& sourceCrop = mState.sourceCrop;
+    return sourceCrop.getHeight() != displayFrame.getHeight() ||
+            sourceCrop.getWidth() != displayFrame.getWidth();
+}
+
 void OutputLayer::dump(std::string& out) const {
     using android::base::StringAppendF;
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index e3be0d7..743da82 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -30,6 +30,7 @@
 
 #include "MockHWC2.h"
 #include "MockHWComposer.h"
+#include "MockPowerAdvisor.h"
 
 namespace android::compositionengine {
 namespace {
@@ -59,6 +60,7 @@
     }
 
     StrictMock<android::mock::HWComposer> mHwComposer;
+    StrictMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor;
     StrictMock<mock::CompositionEngine> mCompositionEngine;
     sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
     StrictMock<HWC2::mock::Layer> mHWC2Layer1;
@@ -68,7 +70,10 @@
     mock::OutputLayer* mLayer2 = new StrictMock<mock::OutputLayer>();
     mock::OutputLayer* mLayer3 = new StrictMock<mock::OutputLayer>();
     impl::Display mDisplay{mCompositionEngine,
-                           DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+                           DisplayCreationArgsBuilder()
+                                   .setDisplayId(DEFAULT_DISPLAY_ID)
+                                   .setPowerAdvisor(&mPowerAdvisor)
+                                   .build()};
 };
 
 /*
@@ -344,6 +349,24 @@
 }
 
 /*
+ * Display::getSkipColorTransform()
+ */
+
+TEST_F(DisplayTest, getSkipColorTransformDoesNothingIfNonHwcDisplay) {
+    auto nonHwcDisplay{
+            impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+    EXPECT_FALSE(nonHwcDisplay->getSkipColorTransform());
+}
+
+TEST_F(DisplayTest, getSkipColorTransformChecksHwcCapability) {
+    EXPECT_CALL(mHwComposer,
+                hasDisplayCapability(std::make_optional(DEFAULT_DISPLAY_ID),
+                                     HWC2::DisplayCapability::SkipClientColorTransform))
+            .WillOnce(Return(true));
+    EXPECT_TRUE(mDisplay.getSkipColorTransform());
+}
+
+/*
  * Display::anyLayersRequireClientComposition()
  */
 
@@ -502,5 +525,17 @@
     EXPECT_EQ(layer2Fence, result.layerFences[&mHWC2Layer2]);
 }
 
+/*
+ * Display::setExpensiveRenderingExpected()
+ */
+
+TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) {
+    EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, true)).Times(1);
+    mDisplay.setExpensiveRenderingExpected(true);
+
+    EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, false)).Times(1);
+    mDisplay.setExpensiveRenderingExpected(false);
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
new file mode 100644
index 0000000..85b9403
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockPowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+
+// This will go away once PowerAdvisor is moved into the "backend" library
+PowerAdvisor::~PowerAdvisor() = default;
+
+namespace mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+PowerAdvisor::PowerAdvisor() = default;
+PowerAdvisor::~PowerAdvisor() = default;
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
new file mode 100644
index 0000000..c5a73f2
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "DisplayHardware/PowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+namespace mock {
+
+class PowerAdvisor : public android::Hwc2::PowerAdvisor {
+public:
+    PowerAdvisor();
+    ~PowerAdvisor() override;
+
+    MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
+};
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index a5428ad..c83cae6 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -875,5 +875,23 @@
     EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
 }
 
+/*
+ * OutputLayer::needsFiltering()
+ */
+
+TEST_F(OutputLayerTest, needsFilteringReturnsFalseIfDisplaySizeSameAsSourceSize) {
+    mOutputLayer.editState().displayFrame = Rect(100, 100, 200, 200);
+    mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.f, 100.f};
+
+    EXPECT_FALSE(mOutputLayer.needsFiltering());
+}
+
+TEST_F(OutputLayerTest, needsFilteringReturnsTrueIfDisplaySizeDifferentFromSourceSize) {
+    mOutputLayer.editState().displayFrame = Rect(100, 100, 200, 200);
+    mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.1f, 100.1f};
+
+    EXPECT_TRUE(mOutputLayer.needsFiltering());
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index d136562..b6d79d4 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -60,7 +60,7 @@
         mDisplayInstallOrientation(args.displayInstallOrientation),
         mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
                 compositionengine::DisplayCreationArgs{args.isSecure, args.isVirtual,
-                                                       args.displayId})},
+                                                       args.displayId, args.powerAdvisor})},
         mIsVirtual(args.isVirtual),
         mOrientation(),
         mActiveConfig(0),
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 8bc19d4..4321e3d 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -40,6 +40,7 @@
 #include <utils/Timers.h>
 
 #include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/PowerAdvisor.h"
 #include "RenderArea.h"
 
 namespace android {
@@ -241,6 +242,7 @@
     std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
     int initialPowerMode{HWC_POWER_MODE_NORMAL};
     bool isPrimary{false};
+    Hwc2::PowerAdvisor* powerAdvisor{nullptr};
 };
 
 class DisplayRenderArea : public RenderArea {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7dfc3a7..db4ae41 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -440,6 +440,7 @@
 }
 
 void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compositionState) const {
+    const auto& drawingState{getDrawingState()};
     compositionState.forceClientComposition = false;
 
     // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
@@ -451,9 +452,14 @@
     compositionState.colorTransform = getColorTransform();
     compositionState.colorTransformIsIdentity = !hasColorTransform();
     compositionState.surfaceDamage = surfaceDamageRegion;
+    compositionState.hasProtectedContent = isProtected();
+
+    const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
+    compositionState.isOpaque =
+            isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
 
     // Force client composition for special cases known only to the front-end.
-    if (isHdrY410() || getRoundedCornerState().radius > 0.0f) {
+    if (isHdrY410() || usesRoundedCorners) {
         compositionState.forceClientComposition = true;
     }
 }
@@ -1932,46 +1938,10 @@
     }
 }
 
-void Layer::writeToProtoCompositionState(LayerProto* layerInfo,
-                                         const sp<DisplayDevice>& displayDevice,
-                                         uint32_t traceFlags) const {
-    auto outputLayer = findOutputLayerForDisplay(displayDevice);
-    if (!outputLayer) {
-        return;
-    }
-
-    writeToProtoDrawingState(layerInfo, traceFlags);
-    writeToProtoCommonState(layerInfo, LayerVector::StateSet::Drawing, traceFlags);
-
-    const auto& compositionState = outputLayer->getState();
-
-    const Rect& frame = compositionState.displayFrame;
-    LayerProtoHelper::writeToProto(frame, [&]() { return layerInfo->mutable_hwc_frame(); });
-
-    const FloatRect& crop = compositionState.sourceCrop;
-    LayerProtoHelper::writeToProto(crop, [&]() { return layerInfo->mutable_hwc_crop(); });
-
-    const int32_t transform =
-            getCompositionLayer() ? static_cast<int32_t>(compositionState.bufferTransform) : 0;
-    layerInfo->set_hwc_transform(transform);
-
-    const int32_t compositionType =
-            static_cast<int32_t>(compositionState.hwc ? (*compositionState.hwc).hwcCompositionType
-                                                      : Hwc2::IComposerClient::Composition::CLIENT);
-    layerInfo->set_hwc_composition_type(compositionType);
-}
-
 bool Layer::isRemovedFromCurrentState() const  {
     return mRemovedFromCurrentState;
 }
 
-// Debug helper for b/137560795
-#define INT32_MIGHT_OVERFLOW(n) (((n) >= INT32_MAX / 2) || ((n) <= INT32_MIN / 2))
-
-#define RECT_BOUNDS_INVALID(rect)                                               \
-    (INT32_MIGHT_OVERFLOW((rect).left) || INT32_MIGHT_OVERFLOW((rect).right) || \
-     INT32_MIGHT_OVERFLOW((rect).bottom) || INT32_MIGHT_OVERFLOW((rect).top))
-
 InputWindowInfo Layer::fillInputInfo() {
     InputWindowInfo info = mDrawingState.inputInfo;
 
@@ -1982,14 +1952,14 @@
     ui::Transform t = getTransform();
     const float xScale = t.sx();
     const float yScale = t.sy();
-    float xSurfaceInset = info.surfaceInset;
-    float ySurfaceInset = info.surfaceInset;
+    int32_t xSurfaceInset = info.surfaceInset;
+    int32_t ySurfaceInset = info.surfaceInset;
     if (xScale != 1.0f || yScale != 1.0f) {
-        info.windowXScale *= 1.0f / xScale;
-        info.windowYScale *= 1.0f / yScale;
+        info.windowXScale *= (xScale != 0.0f) ? 1.0f / xScale : 0.0f;
+        info.windowYScale *= (yScale != 0.0f) ? 1.0f / yScale : 0.0f;
         info.touchableRegion.scaleSelf(xScale, yScale);
-        xSurfaceInset *= xScale;
-        ySurfaceInset *= yScale;
+        xSurfaceInset = std::round(xSurfaceInset * xScale);
+        ySurfaceInset = std::round(ySurfaceInset * yScale);
     }
 
     // Transform layer size to screen space and inset it by surface insets.
@@ -2002,25 +1972,10 @@
     }
     layerBounds = t.transform(layerBounds);
 
-    // debug check for b/137560795
-    {
-        if (RECT_BOUNDS_INVALID(layerBounds)) {
-            ALOGE("layer %s bounds are invalid (%" PRIi32 ", %" PRIi32 ", %" PRIi32 ", %" PRIi32
-                  ")",
-                  mName.c_str(), layerBounds.left, layerBounds.top, layerBounds.right,
-                  layerBounds.bottom);
-            std::string out;
-            getTransform().dump(out, "Transform");
-            ALOGE("%s", out.c_str());
-            layerBounds.left = layerBounds.top = layerBounds.right = layerBounds.bottom = 0;
-        }
+    // clamp inset to layer bounds
+    xSurfaceInset = (xSurfaceInset >= 0) ? std::min(xSurfaceInset, layerBounds.getWidth() / 2) : 0;
+    ySurfaceInset = (ySurfaceInset >= 0) ? std::min(ySurfaceInset, layerBounds.getHeight() / 2) : 0;
 
-        if (INT32_MIGHT_OVERFLOW(xSurfaceInset) || INT32_MIGHT_OVERFLOW(ySurfaceInset)) {
-            ALOGE("layer %s surface inset are invalid (%" PRIi32 ", %" PRIi32 ")", mName.c_str(),
-                  int32_t(xSurfaceInset), int32_t(ySurfaceInset));
-            xSurfaceInset = ySurfaceInset = 0;
-        }
-    }
     layerBounds.inset(xSurfaceInset, ySurfaceInset, xSurfaceInset, ySurfaceInset);
 
     // Input coordinate should match the layer bounds.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 953f25d..87a5896 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -93,7 +93,7 @@
     LayerMetadata metadata;
 };
 
-class Layer : public virtual compositionengine::LayerFE, public ClientCache::ErasedRecipient {
+class Layer : public virtual compositionengine::LayerFE {
     static std::atomic<int32_t> sSequence;
 
 public:
@@ -440,11 +440,6 @@
     // thread.
     void writeToProtoDrawingState(LayerProto* layerInfo,
                                   uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
-    // Write states that are modified by the main thread. This includes drawing
-    // state as well as buffer data and composition data for layers on the specified
-    // display. This should be called in the main or tracing thread.
-    void writeToProtoCompositionState(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
-                                      uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
     // Write drawing or current state. If writing current state, the caller should hold the
     // external mStateLock. If writing drawing state, this function should be called on the
     // main or tracing thread.
@@ -676,9 +671,6 @@
     compositionengine::OutputLayer* findOutputLayerForDisplay(
             const sp<const DisplayDevice>& display) const;
 
-    // Inherit from ClientCache::ErasedRecipient
-    void bufferErased(const client_cache_t& /*clientCacheId*/) override {}
-
 protected:
     // constant
     sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
deleted file mode 100644
index a2d1feb..0000000
--- a/services/surfaceflinger/LayerStats.cpp
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#undef LOG_TAG
-#define LOG_TAG "LayerStats"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "LayerStats.h"
-#include "DisplayHardware/HWComposer.h"
-#include "ui/DebugUtils.h"
-
-#include <android-base/stringprintf.h>
-#include <log/log.h>
-#include <utils/Trace.h>
-
-namespace android {
-
-using base::StringAppendF;
-using base::StringPrintf;
-
-void LayerStats::enable() {
-    ATRACE_CALL();
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (mEnabled) return;
-    mLayerShapeStatsMap.clear();
-    mEnabled = true;
-    ALOGD("Logging enabled");
-}
-
-void LayerStats::disable() {
-    ATRACE_CALL();
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (!mEnabled) return;
-    mEnabled = false;
-    ALOGD("Logging disabled");
-}
-
-void LayerStats::clear() {
-    ATRACE_CALL();
-    std::lock_guard<std::mutex> lock(mMutex);
-    mLayerShapeStatsMap.clear();
-    ALOGD("Cleared current layer stats");
-}
-
-bool LayerStats::isEnabled() {
-    return mEnabled;
-}
-
-void LayerStats::traverseLayerTreeStatsLocked(
-        const std::vector<LayerProtoParser::Layer*>& layerTree,
-        const LayerProtoParser::LayerGlobal& layerGlobal,
-        std::vector<std::string>* const outLayerShapeVec) {
-    for (const auto& layer : layerTree) {
-        if (!layer) continue;
-        traverseLayerTreeStatsLocked(layer->children, layerGlobal, outLayerShapeVec);
-        std::string key = "";
-        StringAppendF(&key, ",%s", layer->type.c_str());
-        StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
-        StringAppendF(&key, ",%d", layer->isProtected);
-        StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform));
-        StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format).c_str());
-        StringAppendF(&key, ",%s", layer->dataspace.c_str());
-        StringAppendF(&key, ",%s",
-                      destinationLocation(layer->hwcFrame.left, layerGlobal.resolution[0], true));
-        StringAppendF(&key, ",%s",
-                      destinationLocation(layer->hwcFrame.top, layerGlobal.resolution[1], false));
-        StringAppendF(&key, ",%s",
-                      destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
-                                      layerGlobal.resolution[0], true));
-        StringAppendF(&key, ",%s",
-                      destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
-                                      layerGlobal.resolution[1], false));
-        StringAppendF(&key, ",%s", scaleRatioWH(layer).c_str());
-        StringAppendF(&key, ",%s", alpha(static_cast<float>(layer->color.a)));
-
-        outLayerShapeVec->push_back(key);
-        ALOGV("%s", key.c_str());
-    }
-}
-
-void LayerStats::logLayerStats(const LayersProto& layersProto) {
-    ATRACE_CALL();
-    ALOGV("Logging");
-    auto layerGlobal = LayerProtoParser::generateLayerGlobalInfo(layersProto);
-    auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
-    std::vector<std::string> layerShapeVec;
-
-    std::lock_guard<std::mutex> lock(mMutex);
-    traverseLayerTreeStatsLocked(layerTree.topLevelLayers, layerGlobal, &layerShapeVec);
-
-    std::string layerShapeKey =
-            StringPrintf("%d,%s,%s,%s", static_cast<int32_t>(layerShapeVec.size()),
-                         layerGlobal.colorMode.c_str(), layerGlobal.colorTransform.c_str(),
-                         layerTransform(layerGlobal.globalTransform));
-    ALOGV("%s", layerShapeKey.c_str());
-
-    std::sort(layerShapeVec.begin(), layerShapeVec.end(), std::greater<std::string>());
-    for (auto const& s : layerShapeVec) {
-        layerShapeKey += s;
-    }
-
-    mLayerShapeStatsMap[layerShapeKey]++;
-}
-
-void LayerStats::dump(std::string& result) {
-    ATRACE_CALL();
-    ALOGD("Dumping");
-    std::lock_guard<std::mutex> lock(mMutex);
-    result.append("Frequency,LayerCount,ColorMode,ColorTransform,Orientation\n");
-    result.append("LayerType,CompositionType,IsProtected,Transform,PixelFormat,Dataspace,");
-    result.append("DstX,DstY,DstWidth,DstHeight,WScale,HScale,Alpha\n");
-    for (auto& u : mLayerShapeStatsMap) {
-        StringAppendF(&result, "%u,%s\n", u.second, u.first.c_str());
-    }
-}
-
-const char* LayerStats::destinationLocation(int32_t location, int32_t range, bool isHorizontal) {
-    static const char* locationArray[8] = {"0", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8"};
-    int32_t ratio = location * 8 / range;
-    if (ratio < 0) return "N/A";
-    if (isHorizontal) {
-        // X location is divided into 4 buckets {"0", "1/4", "1/2", "3/4"}
-        if (ratio > 6) return "3/4";
-        // use index 0, 2, 4, 6
-        return locationArray[ratio & ~1];
-    }
-    if (ratio > 7) return "7/8";
-    return locationArray[ratio];
-}
-
-const char* LayerStats::destinationSize(int32_t size, int32_t range, bool isWidth) {
-    static const char* sizeArray[8] = {"1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1"};
-    int32_t ratio = size * 8 / range;
-    if (ratio < 0) return "N/A";
-    if (isWidth) {
-        // width is divided into 4 buckets {"1/4", "1/2", "3/4", "1"}
-        if (ratio > 6) return "1";
-        // use index 1, 3, 5, 7
-        return sizeArray[ratio | 1];
-    }
-    if (ratio > 7) return "1";
-    return sizeArray[ratio];
-}
-
-const char* LayerStats::layerTransform(int32_t transform) {
-    return getTransformName(static_cast<hwc_transform_t>(transform));
-}
-
-const char* LayerStats::layerCompositionType(int32_t compositionType) {
-    return getCompositionName(static_cast<hwc2_composition_t>(compositionType));
-}
-
-std::string LayerStats::layerPixelFormat(int32_t pixelFormat) {
-    return decodePixelFormat(pixelFormat);
-}
-
-std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
-    if (!layer->type.compare("ColorLayer")) return "N/A,N/A";
-    std::string ret = "";
-    if (isRotated(layer->hwcTransform)) {
-        ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
-                          static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
-        ret += ",";
-        ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
-                          static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
-    } else {
-        ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
-                          static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
-        ret += ",";
-        ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
-                          static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
-    }
-    return ret;
-}
-
-const char* LayerStats::scaleRatio(int32_t destinationScale, int32_t sourceScale) {
-    // Make scale buckets from <1/64 to >= 16, to avoid floating point
-    // calculation, x64 on destinationScale first
-    int32_t scale = destinationScale * 64 / sourceScale;
-    if (!scale) return "<1/64";
-    if (scale < 2) return "1/64";
-    if (scale < 4) return "1/32";
-    if (scale < 8) return "1/16";
-    if (scale < 16) return "1/8";
-    if (scale < 32) return "1/4";
-    if (scale < 64) return "1/2";
-    if (scale < 128) return "1";
-    if (scale < 256) return "2";
-    if (scale < 512) return "4";
-    if (scale < 1024) return "8";
-    return ">=16";
-}
-
-const char* LayerStats::alpha(float a) {
-    if (a == 1.0f) return "1.0";
-    if (a > 0.9f) return "0.99";
-    if (a > 0.8f) return "0.9";
-    if (a > 0.7f) return "0.8";
-    if (a > 0.6f) return "0.7";
-    if (a > 0.5f) return "0.6";
-    if (a > 0.4f) return "0.5";
-    if (a > 0.3f) return "0.4";
-    if (a > 0.2f) return "0.3";
-    if (a > 0.1f) return "0.2";
-    if (a > 0.0f) return "0.1";
-    return "0.0";
-}
-
-bool LayerStats::isRotated(int32_t transform) {
-    return transform & HWC_TRANSFORM_ROT_90;
-}
-
-bool LayerStats::isVFlipped(int32_t transform) {
-    return transform & HWC_TRANSFORM_FLIP_V;
-}
-
-bool LayerStats::isHFlipped(int32_t transform) {
-    return transform & HWC_TRANSFORM_FLIP_H;
-}
-
-}  // namespace android
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
deleted file mode 100644
index 62b2688..0000000
--- a/services/surfaceflinger/LayerStats.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <layerproto/LayerProtoHeader.h>
-#include <layerproto/LayerProtoParser.h>
-#include <mutex>
-#include <unordered_map>
-
-using namespace android::surfaceflinger;
-
-namespace android {
-
-class LayerStats {
-public:
-    void enable();
-    void disable();
-    void clear();
-    bool isEnabled();
-    void logLayerStats(const LayersProto& layersProto);
-    void dump(std::string& result);
-
-private:
-    // Traverse layer tree to get all visible layers' stats
-    void traverseLayerTreeStatsLocked(
-            const std::vector<LayerProtoParser::Layer*>& layerTree,
-            const LayerProtoParser::LayerGlobal& layerGlobal,
-            std::vector<std::string>* const outLayerShapeVec);
-    // Convert layer's top-left position into 8x8 percentage of the display
-    static const char* destinationLocation(int32_t location, int32_t range, bool isHorizontal);
-    // Convert layer's size into 8x8 percentage of the display
-    static const char* destinationSize(int32_t size, int32_t range, bool isWidth);
-    // Return the name of the transform
-    static const char* layerTransform(int32_t transform);
-    // Return the name of the composition type
-    static const char* layerCompositionType(int32_t compositionType);
-    // Return the name of the pixel format
-    static std::string layerPixelFormat(int32_t pixelFormat);
-    // Calculate scale ratios of layer's width/height with rotation information
-    static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
-    // Calculate scale ratio from source to destination and convert to string
-    static const char* scaleRatio(int32_t destinationScale, int32_t sourceScale);
-    // Bucket the alpha into designed buckets
-    static const char* alpha(float a);
-    // Return whether the original buffer is rotated in final composition
-    static bool isRotated(int32_t transform);
-    // Return whether the original buffer is V-flipped in final composition
-    static bool isVFlipped(int32_t transform);
-    // Return whether the original buffer is H-flipped in final composition
-    static bool isHFlipped(int32_t transform);
-
-    bool mEnabled = false;
-    // Protect mLayersStatsMap
-    std::mutex mMutex;
-    // Hashmap for tracking the frame(layer shape) stats
-    // KEY is a concatenation of all layers' properties within a frame
-    // VALUE is the number of times this particular set has been scanned out
-    std::unordered_map<std::string, uint32_t> mLayerShapeStatsMap;
-};
-
-}  // namespace android
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index e782dd5..723d71f 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -49,7 +49,7 @@
     mLastPresentTime = lastPresentTime;
     // Ignore time diff that are too high - those are stale values
     if (timeDiff > OBSOLETE_TIME_EPSILON_NS.count()) return;
-    const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration;
+    const nsecs_t refreshDuration = std::max(timeDiff, mMinRefreshDuration);
     const int fps = 1e9f / refreshDuration;
     mRefreshRateHistory.insertRefreshRate(fps);
 }
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 952643c..3883427 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -118,6 +118,14 @@
     }
 }
 
+Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync,
+                     std::unique_ptr<EventControlThread> eventControlThread,
+                     const scheduler::RefreshRateConfigs& configs)
+      : mHasSyncFramework(false),
+        mPrimaryDispSync(std::move(primaryDispSync)),
+        mEventControlThread(std::move(eventControlThread)),
+        mRefreshRateConfigs(configs) {}
+
 Scheduler::~Scheduler() {
     // Ensure the OneShotTimer threads are joined before we start destroying state.
     mDisplayPowerTimer.reset();
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0d9d7aa..5905ff6 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -204,6 +204,10 @@
     enum class TimerState { Reset, Expired };
     enum class TouchState { Inactive, Active };
 
+    // Used by tests to inject mocks.
+    Scheduler(std::unique_ptr<DispSync>, std::unique_ptr<EventControlThread>,
+              const scheduler::RefreshRateConfigs&);
+
     // Creates a connection on the given EventThread and forwards the given callbacks.
     sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
                                                        ISurfaceComposer::ConfigChanged);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 488b9ef..04e7bf5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1798,8 +1798,6 @@
         doComposition(displayDevice, repaintEverything);
     }
 
-    logLayerStats();
-
     postFrame();
     postComposition();
 
@@ -1904,6 +1902,10 @@
         auto display = displayDevice->getCompositionDisplay();
 
         for (auto& layer : display->getOutputLayersOrderedByZ()) {
+            if (mDebugDisableHWC || mDebugRegion) {
+                layer->editState().forceClientComposition = true;
+            }
+
             // Update the composition state of the output layer, as needed
             // recomputing it from the state given by the front-end layer.
             layer->updateCompositionState(updatingGeometryThisFrame);
@@ -1943,7 +1945,7 @@
         if (!dirtyRegion.isEmpty()) {
             base::unique_fd readyFence;
             // redraw the whole screen
-            doComposeSurfaces(displayDevice, dirtyRegion, &readyFence);
+            display->composeSurfaces(dirtyRegion, &readyFence);
 
             display->getRenderSurface()->queueBuffer(std::move(readyFence));
         }
@@ -1958,20 +1960,6 @@
     displayDevice->getCompositionDisplay()->prepareFrame();
 }
 
-void SurfaceFlinger::logLayerStats() {
-    ATRACE_CALL();
-    if (CC_UNLIKELY(mLayerStats.isEnabled())) {
-        for (const auto& [token, display] : mDisplays) {
-            if (display->isPrimary()) {
-                mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(display));
-                return;
-            }
-        }
-
-        ALOGE("logLayerStats: no primary display");
-    }
-}
-
 void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
                                             std::shared_ptr<FenceTime>& presentFenceTime) {
     // Update queue of past composite+present times and determine the
@@ -2488,6 +2476,7 @@
     creationArgs.displaySurface = dispSurface;
     creationArgs.hasWideColorGamut = false;
     creationArgs.supportedPerFrameMetadata = 0;
+    creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr;
 
     const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
     creationArgs.isPrimary = isInternalDisplay;
@@ -3228,201 +3217,12 @@
 
     ALOGV("doDisplayComposition");
     base::unique_fd readyFence;
-    if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return;
+    if (!display->composeSurfaces(Region::INVALID_REGION, &readyFence)) return;
 
     // swap buffers (presentation)
     display->getRenderSurface()->queueBuffer(std::move(readyFence));
 }
 
-bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice,
-                                       const Region& debugRegion, base::unique_fd* readyFence) {
-    ATRACE_CALL();
-    ALOGV("doComposeSurfaces");
-
-    auto display = displayDevice->getCompositionDisplay();
-    const auto& displayState = display->getState();
-    const auto displayId = display->getId();
-    auto& renderEngine = getRenderEngine();
-    const bool supportProtectedContent = renderEngine.supportsProtectedContent();
-
-    const Region bounds(displayState.bounds);
-    const DisplayRenderArea renderArea(displayDevice);
-    const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
-                                                      displayState.usesClientComposition};
-    bool applyColorMatrix = false;
-
-    renderengine::DisplaySettings clientCompositionDisplay;
-    std::vector<renderengine::LayerSettings> clientCompositionLayers;
-    sp<GraphicBuffer> buf;
-    base::unique_fd fd;
-
-    if (hasClientComposition) {
-        ALOGV("hasClientComposition");
-
-        if (displayDevice->isPrimary() && supportProtectedContent) {
-            bool needsProtected = false;
-            for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-                // If the layer is a protected layer, mark protected context is needed.
-                if (layer->isProtected()) {
-                    needsProtected = true;
-                    break;
-                }
-            }
-            if (needsProtected != renderEngine.isProtected()) {
-                renderEngine.useProtectedContext(needsProtected);
-            }
-            if (needsProtected != display->getRenderSurface()->isProtected() &&
-                needsProtected == renderEngine.isProtected()) {
-                display->getRenderSurface()->setProtected(needsProtected);
-            }
-        }
-
-        buf = display->getRenderSurface()->dequeueBuffer(&fd);
-
-        if (buf == nullptr) {
-            ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
-                  "client composition for this frame",
-                  displayDevice->getDisplayName().c_str());
-            return false;
-        }
-
-        clientCompositionDisplay.physicalDisplay = displayState.scissor;
-        clientCompositionDisplay.clip = displayState.scissor;
-        const ui::Transform& displayTransform = displayState.transform;
-        clientCompositionDisplay.globalTransform = displayTransform.asMatrix4();
-        clientCompositionDisplay.orientation = displayState.orientation;
-
-        const auto* profile = display->getDisplayColorProfile();
-        Dataspace outputDataspace = Dataspace::UNKNOWN;
-        if (profile->hasWideColorGamut()) {
-            outputDataspace = displayState.dataspace;
-        }
-        clientCompositionDisplay.outputDataspace = outputDataspace;
-        clientCompositionDisplay.maxLuminance =
-                profile->getHdrCapabilities().getDesiredMaxLuminance();
-
-        const bool hasDeviceComposition = displayState.usesDeviceComposition;
-        const bool skipClientColorTransform =
-                getHwComposer()
-                        .hasDisplayCapability(displayId,
-                                              HWC2::DisplayCapability::SkipClientColorTransform);
-
-        // Compute the global color transform matrix.
-        applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
-        if (applyColorMatrix) {
-            clientCompositionDisplay.colorTransform = displayState.colorTransformMat;
-        }
-    }
-
-    /*
-     * and then, render the layers targeted at the framebuffer
-     */
-
-    ALOGV("Rendering client layers");
-    const bool useIdentityTransform = false;
-    bool firstLayer = true;
-    Region clearRegion = Region::INVALID_REGION;
-    for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-        const Region viewportRegion(displayState.viewport);
-        const Region clip(viewportRegion.intersect(layer->visibleRegion));
-        ALOGV("Layer: %s", layer->getName().string());
-        ALOGV("  Composition type: %s", toString(layer->getCompositionType(displayDevice)).c_str());
-        if (!clip.isEmpty()) {
-            switch (layer->getCompositionType(displayDevice)) {
-                case Hwc2::IComposerClient::Composition::CURSOR:
-                case Hwc2::IComposerClient::Composition::DEVICE:
-                case Hwc2::IComposerClient::Composition::SIDEBAND:
-                case Hwc2::IComposerClient::Composition::SOLID_COLOR: {
-                    LOG_ALWAYS_FATAL_IF(!displayId);
-                    const Layer::State& state(layer->getDrawingState());
-                    if (layer->getClearClientTarget(displayDevice) && !firstLayer &&
-                        layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
-                        layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
-                        // never clear the very first layer since we're
-                        // guaranteed the FB is already cleared
-                        Region dummyRegion;
-                        compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
-                                clip,
-                                useIdentityTransform,
-                                layer->needsFiltering(renderArea.getDisplayDevice()) ||
-                                        renderArea.needsFiltering(),
-                                renderArea.isSecure(),
-                                supportProtectedContent,
-                                dummyRegion,
-                        };
-                        auto result = layer->prepareClientComposition(targetSettings);
-
-                        if (result) {
-                            auto& layerSettings = *result;
-                            layerSettings.source.buffer.buffer = nullptr;
-                            layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
-                            layerSettings.alpha = half(0.0);
-                            layerSettings.disableBlending = true;
-                            clientCompositionLayers.push_back(layerSettings);
-                        }
-                    }
-                    break;
-                }
-                case Hwc2::IComposerClient::Composition::CLIENT: {
-                    compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
-                            clip,
-                            useIdentityTransform,
-                            layer->needsFiltering(renderArea.getDisplayDevice()) ||
-                                    renderArea.needsFiltering(),
-                            renderArea.isSecure(),
-                            supportProtectedContent,
-                            clearRegion,
-                    };
-                    auto result = layer->prepareClientComposition(targetSettings);
-                    if (result) {
-                        clientCompositionLayers.push_back(*result);
-                    }
-                    break;
-                }
-                default:
-                    break;
-            }
-        } else {
-            ALOGV("  Skipping for empty clip");
-        }
-        firstLayer = false;
-    }
-
-    // Perform some cleanup steps if we used client composition.
-    if (hasClientComposition) {
-        clientCompositionDisplay.clearRegion = clearRegion;
-
-        // We boost GPU frequency here because there will be color spaces conversion
-        // and it's expensive. We boost the GPU frequency so that GPU composition can
-        // finish in time. We must reset GPU frequency afterwards, because high frequency
-        // consumes extra battery.
-        const bool expensiveRenderingExpected =
-                clientCompositionDisplay.outputDataspace == Dataspace::DISPLAY_P3;
-        if (expensiveRenderingExpected && displayId) {
-            mPowerAdvisor.setExpensiveRenderingExpected(*displayId, true);
-        }
-        if (!debugRegion.isEmpty()) {
-            Region::const_iterator it = debugRegion.begin();
-            Region::const_iterator end = debugRegion.end();
-            while (it != end) {
-                const Rect& rect = *it++;
-                renderengine::LayerSettings layerSettings;
-                layerSettings.source.buffer.buffer = nullptr;
-                layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
-                layerSettings.geometry.boundaries = rect.toFloatRect();
-                layerSettings.alpha = half(1.0);
-                clientCompositionLayers.push_back(layerSettings);
-            }
-        }
-        renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
-                                buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
-                                readyFence);
-    } else if (displayId) {
-        mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
-    }
-    return true;
-}
-
 status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
                                         const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
                                         const sp<IBinder>& parentHandle,
@@ -3441,7 +3241,7 @@
         }
 
         if (mNumLayers >= MAX_LAYERS) {
-            ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers,
+            ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
                   MAX_LAYERS);
             return NO_MEMORY;
         }
@@ -3465,7 +3265,7 @@
                                         mMaxGraphicBufferProducerListSize,
                                 "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
                                 mGraphicBufferProducerList.size(),
-                                mMaxGraphicBufferProducerListSize, mNumLayers);
+                                mMaxGraphicBufferProducerListSize, mNumLayers.load());
         }
         mLayersAdded = true;
     }
@@ -3677,6 +3477,7 @@
 
     if (uncacheBuffer.isValid()) {
         ClientCache::getInstance().erase(uncacheBuffer);
+        getRenderEngine().unbindExternalTextureBuffer(uncacheBuffer.id);
     }
 
     // If a synchronous transaction is explicitly requested without any changes, force a transaction
@@ -4039,12 +3840,18 @@
     bool bufferChanged = what & layer_state_t::eBufferChanged;
     bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
     sp<GraphicBuffer> buffer;
-    if (bufferChanged && cacheIdChanged) {
-        ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
-        ClientCache::getInstance().registerErasedRecipient(s.cachedBuffer,
-                                                           wp<ClientCache::ErasedRecipient>(layer));
-        getRenderEngine().cacheExternalTextureBuffer(s.buffer);
+    if (bufferChanged && cacheIdChanged && s.buffer != nullptr) {
         buffer = s.buffer;
+        bool success = ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
+        if (success) {
+            getRenderEngine().cacheExternalTextureBuffer(s.buffer);
+            success = ClientCache::getInstance()
+                              .registerErasedRecipient(s.cachedBuffer,
+                                                       wp<ClientCache::ErasedRecipient>(this));
+            if (!success) {
+                getRenderEngine().unbindExternalTextureBuffer(s.buffer->getId());
+            }
+        }
     } else if (cacheIdChanged) {
         buffer = ClientCache::getInstance().get(s.cachedBuffer);
     } else if (bufferChanged) {
@@ -4465,14 +4272,10 @@
         using namespace std::string_literals;
 
         static const std::unordered_map<std::string, Dumper> dumpers = {
-                {"--clear-layer-stats"s, dumper([this](std::string&) { mLayerStats.clear(); })},
-                {"--disable-layer-stats"s, dumper([this](std::string&) { mLayerStats.disable(); })},
                 {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
                 {"--dispsync"s, dumper([this](std::string& s) {
                          mScheduler->dumpPrimaryDispSync(s);
                  })},
-                {"--dump-layer-stats"s, dumper([this](std::string& s) { mLayerStats.dump(s); })},
-                {"--enable-layer-stats"s, dumper([this](std::string&) { mLayerStats.enable(); })},
                 {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
                 {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
                 {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
@@ -4485,7 +4288,8 @@
 
         const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
 
-        if (const auto it = dumpers.find(flag); it != dumpers.end()) {
+        const auto it = dumpers.find(flag);
+        if (it != dumpers.end()) {
             (it->second)(args, asProto, result);
         } else if (!asProto) {
             dumpAllLocked(args, result);
@@ -4495,13 +4299,15 @@
             mStateLock.unlock();
         }
 
-        LayersProto layersProto = dumpProtoFromMainThread();
-        if (asProto) {
-            result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
-        } else {
-            auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
-            result.append(LayerProtoParser::layerTreeToString(layerTree));
-            result.append("\n");
+        if (it == dumpers.end()) {
+            const LayersProto layersProto = dumpProtoFromMainThread();
+            if (asProto) {
+                result.append(layersProto.SerializeAsString());
+            } else {
+                const auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+                result.append(LayerProtoParser::layerTreeToString(layerTree));
+                result.append("\n");
+            }
         }
     }
     write(fd, result.c_str(), result.size());
@@ -4760,33 +4566,6 @@
     return layersProto;
 }
 
-LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(
-        const sp<DisplayDevice>& displayDevice) const {
-    LayersProto layersProto;
-
-    SizeProto* resolution = layersProto.mutable_resolution();
-    resolution->set_w(displayDevice->getWidth());
-    resolution->set_h(displayDevice->getHeight());
-
-    auto display = displayDevice->getCompositionDisplay();
-    const auto& displayState = display->getState();
-
-    layersProto.set_color_mode(decodeColorMode(displayState.colorMode));
-    layersProto.set_color_transform(decodeColorTransform(displayState.colorTransform));
-    layersProto.set_global_transform(displayState.orientation);
-
-    const auto displayId = displayDevice->getId();
-    LOG_ALWAYS_FATAL_IF(!displayId);
-    mDrawingState.traverseInZOrder([&](Layer* layer) {
-        if (!layer->visibleRegion.isEmpty() && !display->getOutputLayersOrderedByZ().empty()) {
-            LayerProto* layerProto = layersProto.add_layers();
-            layer->writeToProtoCompositionState(layerProto, displayDevice);
-        }
-    });
-
-    return layersProto;
-}
-
 void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
     const bool colorize = !args.empty() && args[0] == String16("--color");
     Colorizer colorizer(colorize);
@@ -4839,7 +4618,7 @@
      * Dump the visible layer list
      */
     colorizer.bold(result);
-    StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers);
+    StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers.load());
     StringAppendF(&result, "GraphicBufferProducers: %zu, max %zu\n",
                   mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize);
     colorizer.reset(result);
@@ -5645,10 +5424,13 @@
                 drawLayers();
             } else {
                 Rect bounds = getBounds();
-                screenshotParentLayer = mFlinger->getFactory().createContainerLayer(
-                        LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
-                                          bounds.getWidth(), bounds.getHeight(), 0,
-                                          LayerMetadata()));
+                // In the "childrenOnly" case we reparent the children to a screenshot
+                // layer which has no properties set and which does not draw.
+                sp<ContainerLayer> screenshotParentLayer =
+                        mFlinger->getFactory().createContainerLayer(
+                                LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
+                                                  bounds.getWidth(), bounds.getHeight(), 0,
+                                                  LayerMetadata()));
 
                 ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
                 drawLayers();
@@ -5659,9 +5441,6 @@
         const sp<Layer> mLayer;
         const Rect mCrop;
 
-        // In the "childrenOnly" case we reparent the children to a screenshot
-        // layer which has no properties set and which does not draw.
-        sp<ContainerLayer> screenshotParentLayer;
         ui::Transform mTransform;
         bool mNeedsFiltering;
 
@@ -6096,6 +5875,10 @@
     return nullptr;
 }
 
+void SurfaceFlinger::bufferErased(const client_cache_t& clientCacheId) {
+    getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id);
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3974a8c..e199ad5 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -52,7 +52,6 @@
 #include "DisplayHardware/PowerAdvisor.h"
 #include "Effects/Daltonizer.h"
 #include "FrameTracker.h"
-#include "LayerStats.h"
 #include "LayerVector.h"
 #include "Scheduler/RefreshRateConfigs.h"
 #include "Scheduler/RefreshRateStats.h"
@@ -172,9 +171,9 @@
 
 class SurfaceFlinger : public BnSurfaceComposer,
                        public PriorityDumper,
+                       public ClientCache::ErasedRecipient,
                        private IBinder::DeathRecipient,
-                       private HWC2::ComposerCallback
-{
+                       private HWC2::ComposerCallback {
 public:
     SurfaceFlingerBE& getBE() { return mBE; }
     const SurfaceFlingerBE& getBE() const { return mBE; }
@@ -322,6 +321,9 @@
 
     sp<Layer> fromHandle(const sp<IBinder>& handle) REQUIRES(mStateLock);
 
+    // Inherit from ClientCache::ErasedRecipient
+    void bufferErased(const client_cache_t& clientCacheId) override;
+
 private:
     friend class BufferLayer;
     friend class BufferQueueLayer;
@@ -762,15 +764,8 @@
     void calculateWorkingSet();
     void doComposition(const sp<DisplayDevice>& display, bool repainEverything);
     void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
-    void logLayerStats();
     void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion);
 
-    // This fails if using GL and the surface has been destroyed. readyFence
-    // will be populated if using GL and native fence sync is supported, to
-    // signal when drawing has completed.
-    bool doComposeSurfaces(const sp<DisplayDevice>& display, const Region& debugRegionm,
-                           base::unique_fd* readyFence);
-
     void postFrame();
 
     /* ------------------------------------------------------------------------
@@ -884,7 +879,6 @@
     LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL)
             EXCLUDES(mStateLock);
     void withTracingLock(std::function<void()> operation) REQUIRES(mStateLock);
-    LayersProto dumpVisibleLayersProtoInfo(const sp<DisplayDevice>& display) const;
 
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
@@ -1001,7 +995,6 @@
     SurfaceTracing mTracing{*this};
     bool mTracingEnabled = false;
     bool mTracingEnabledChanged GUARDED_BY(mStateLock) = false;
-    LayerStats mLayerStats;
     const std::shared_ptr<TimeStats> mTimeStats;
     bool mUseHwcVirtualDisplays = false;
     std::atomic<uint32_t> mFrameMissedCount = 0;
@@ -1072,7 +1065,7 @@
     // Static screen stats
     bool mHasPoweredOff = false;
 
-    size_t mNumLayers = 0;
+    std::atomic<size_t> mNumLayers = 0;
 
     // Verify that transaction is being called by an approved process:
     // either AID_GRAPHICS or AID_SYSTEM.
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index c97a19b..93fe7d0 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -173,8 +173,8 @@
         ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
               timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
 
-        const std::string& layerName = layerRecord.layerName;
         if (prevTimeRecord.ready) {
+            const std::string& layerName = layerRecord.layerName;
             if (!mTimeStats.stats.count(layerName)) {
                 mTimeStats.stats[layerName].layerName = layerName;
                 mTimeStats.stats[layerName].packageName = getPackageName(layerName);
@@ -220,18 +220,6 @@
                   timeRecords[0].frameTime.frameNumber, presentToPresentMs);
             timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
         }
-
-        // Output additional trace points to track frame time.
-        ATRACE_INT64(("TimeStats-Post - " + layerName).c_str(), timeRecords[0].frameTime.postTime);
-        ATRACE_INT64(("TimeStats-Acquire - " + layerName).c_str(),
-                     timeRecords[0].frameTime.acquireTime);
-        ATRACE_INT64(("TimeStats-Latch - " + layerName).c_str(),
-                     timeRecords[0].frameTime.latchTime);
-        ATRACE_INT64(("TimeStats-Desired - " + layerName).c_str(),
-                     timeRecords[0].frameTime.desiredTime);
-        ATRACE_INT64(("TimeStats-Present - " + layerName).c_str(),
-                     timeRecords[0].frameTime.presentTime);
-
         prevTimeRecord = timeRecords[0];
         timeRecords.pop_front();
         layerRecord.waitData--;
@@ -613,7 +601,7 @@
     if (asProto) {
         ALOGD("Dumping TimeStats as proto");
         SFTimeStatsGlobalProto timeStatsProto = mTimeStats.toProto(maxLayers);
-        result.append(timeStatsProto.SerializeAsString().c_str(), timeStatsProto.ByteSize());
+        result.append(timeStatsProto.SerializeAsString());
     } else {
         ALOGD("Dumping TimeStats as text");
         result.append(mTimeStats.toString(maxLayers));
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index d3381e5..ef488bd 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -37,16 +37,6 @@
     return lhs->id < rhs->id;
 }
 
-const LayerProtoParser::LayerGlobal LayerProtoParser::generateLayerGlobalInfo(
-        const LayersProto& layersProto) {
-    LayerGlobal layerGlobal;
-    layerGlobal.resolution = {layersProto.resolution().w(), layersProto.resolution().h()};
-    layerGlobal.colorMode = layersProto.color_mode();
-    layerGlobal.colorTransform = layersProto.color_transform();
-    layerGlobal.globalTransform = layersProto.global_transform();
-    return layerGlobal;
-}
-
 LayerProtoParser::LayerTree LayerProtoParser::generateLayerTree(const LayersProto& layersProto) {
     LayerTree layerTree;
     layerTree.allLayers = generateLayerList(layersProto);
@@ -114,10 +104,6 @@
     layer.bufferTransform = generateTransform(layerProto.buffer_transform());
     layer.queuedFrames = layerProto.queued_frames();
     layer.refreshPending = layerProto.refresh_pending();
-    layer.hwcFrame = generateRect(layerProto.hwc_frame());
-    layer.hwcCrop = generateFloatRect(layerProto.hwc_crop());
-    layer.hwcTransform = layerProto.hwc_transform();
-    layer.hwcCompositionType = layerProto.hwc_composition_type();
     layer.isProtected = layerProto.is_protected();
     layer.cornerRadius = layerProto.corner_radius();
     for (const auto& entry : layerProto.metadata()) {
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index d1b2b1f..54e02ca 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -108,10 +108,6 @@
         Transform bufferTransform;
         int32_t queuedFrames;
         bool refreshPending;
-        LayerProtoParser::Rect hwcFrame;
-        LayerProtoParser::FloatRect hwcCrop;
-        int32_t hwcTransform;
-        int32_t hwcCompositionType;
         bool isProtected;
         float cornerRadius;
         LayerMetadata metadata;
@@ -119,14 +115,6 @@
         std::string to_string() const;
     };
 
-    class LayerGlobal {
-    public:
-        int2 resolution;
-        std::string colorMode;
-        std::string colorTransform;
-        int32_t globalTransform;
-    };
-
     class LayerTree {
     public:
         // all layers in LayersProto and in the original order
@@ -136,7 +124,6 @@
         std::vector<Layer*> topLevelLayers;
     };
 
-    static const LayerGlobal generateLayerGlobalInfo(const LayersProto& layersProto);
     static LayerTree generateLayerTree(const LayersProto& layersProto);
     static std::string layerTreeToString(const LayerTree& layerTree);
 
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index b097505..c7fbff3 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -7,10 +7,6 @@
 // Contains a list of all layers.
 message LayersProto {
   repeated LayerProto layers = 1;
-  SizeProto resolution = 2;
-  string color_mode = 3;
-  string color_transform = 4;
-  int32 global_transform = 5;
 }
 
 // Information about each layer.
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
new file mode 100644
index 0000000..b66e56e
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -0,0 +1,138 @@
+props {
+  module: "android.sysprop.SurfaceFlingerProperties"
+  prop {
+    api_name: "color_space_agnostic_dataspace"
+    type: Long
+    prop_name: "ro.surface_flinger.color_space_agnostic_dataspace"
+  }
+  prop {
+    api_name: "default_composition_dataspace"
+    type: Long
+    prop_name: "ro.surface_flinger.default_composition_dataspace"
+  }
+  prop {
+    api_name: "default_composition_pixel_format"
+    type: Integer
+    prop_name: "ro.surface_flinger.default_composition_pixel_format"
+  }
+  prop {
+    api_name: "display_primary_blue"
+    type: DoubleList
+    prop_name: "ro.surface_flinger.display_primary_blue"
+  }
+  prop {
+    api_name: "display_primary_green"
+    type: DoubleList
+    prop_name: "ro.surface_flinger.display_primary_green"
+  }
+  prop {
+    api_name: "display_primary_red"
+    type: DoubleList
+    prop_name: "ro.surface_flinger.display_primary_red"
+  }
+  prop {
+    api_name: "display_primary_white"
+    type: DoubleList
+    prop_name: "ro.surface_flinger.display_primary_white"
+  }
+  prop {
+    api_name: "enable_protected_contents"
+    prop_name: "ro.surface_flinger.protected_contents"
+  }
+  prop {
+    api_name: "force_hwc_copy_for_virtual_displays"
+    prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays"
+  }
+  prop {
+    api_name: "has_HDR_display"
+    prop_name: "ro.surface_flinger.has_HDR_display"
+  }
+  prop {
+    api_name: "has_wide_color_display"
+    prop_name: "ro.surface_flinger.has_wide_color_display"
+  }
+  prop {
+    api_name: "max_frame_buffer_acquired_buffers"
+    type: Long
+    prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
+  }
+  prop {
+    api_name: "max_virtual_display_dimension"
+    type: Long
+    prop_name: "ro.surface_flinger.max_virtual_display_dimension"
+  }
+  prop {
+    api_name: "present_time_offset_from_vsync_ns"
+    type: Long
+    prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns"
+  }
+  prop {
+    api_name: "primary_display_orientation"
+    type: Enum
+    prop_name: "ro.surface_flinger.primary_display_orientation"
+    enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270"
+  }
+  prop {
+    api_name: "running_without_sync_framework"
+    prop_name: "ro.surface_flinger.running_without_sync_framework"
+  }
+  prop {
+    api_name: "set_display_power_timer_ms"
+    type: Integer
+    prop_name: "ro.surface_flinger.set_display_power_timer_ms"
+  }
+  prop {
+    api_name: "set_idle_timer_ms"
+    type: Integer
+    prop_name: "ro.surface_flinger.set_idle_timer_ms"
+  }
+  prop {
+    api_name: "set_touch_timer_ms"
+    type: Integer
+    prop_name: "ro.surface_flinger.set_touch_timer_ms"
+  }
+  prop {
+    api_name: "start_graphics_allocator_service"
+    prop_name: "ro.surface_flinger.start_graphics_allocator_service"
+  }
+  prop {
+    api_name: "support_kernel_idle_timer"
+    prop_name: "ro.surface_flinger.support_kernel_idle_timer"
+  }
+  prop {
+    api_name: "use_color_management"
+    prop_name: "ro.surface_flinger.use_color_management"
+  }
+  prop {
+    api_name: "use_context_priority"
+    prop_name: "ro.surface_flinger.use_context_priority"
+  }
+  prop {
+    api_name: "use_smart_90_for_video"
+    prop_name: "ro.surface_flinger.use_smart_90_for_video"
+  }
+  prop {
+    api_name: "use_vr_flinger"
+    prop_name: "ro.surface_flinger.use_vr_flinger"
+  }
+  prop {
+    api_name: "vsync_event_phase_offset_ns"
+    type: Long
+    prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns"
+  }
+  prop {
+    api_name: "vsync_sf_event_phase_offset_ns"
+    type: Long
+    prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns"
+  }
+  prop {
+    api_name: "wcg_composition_dataspace"
+    type: Long
+    prop_name: "ro.surface_flinger.wcg_composition_dataspace"
+  }
+  prop {
+    api_name: "wcg_composition_pixel_format"
+    type: Integer
+    prop_name: "ro.surface_flinger.wcg_composition_pixel_format"
+  }
+}
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
new file mode 100644
index 0000000..b66e56e
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
@@ -0,0 +1,138 @@
+props {
+  module: "android.sysprop.SurfaceFlingerProperties"
+  prop {
+    api_name: "color_space_agnostic_dataspace"
+    type: Long
+    prop_name: "ro.surface_flinger.color_space_agnostic_dataspace"
+  }
+  prop {
+    api_name: "default_composition_dataspace"
+    type: Long
+    prop_name: "ro.surface_flinger.default_composition_dataspace"
+  }
+  prop {
+    api_name: "default_composition_pixel_format"
+    type: Integer
+    prop_name: "ro.surface_flinger.default_composition_pixel_format"
+  }
+  prop {
+    api_name: "display_primary_blue"
+    type: DoubleList
+    prop_name: "ro.surface_flinger.display_primary_blue"
+  }
+  prop {
+    api_name: "display_primary_green"
+    type: DoubleList
+    prop_name: "ro.surface_flinger.display_primary_green"
+  }
+  prop {
+    api_name: "display_primary_red"
+    type: DoubleList
+    prop_name: "ro.surface_flinger.display_primary_red"
+  }
+  prop {
+    api_name: "display_primary_white"
+    type: DoubleList
+    prop_name: "ro.surface_flinger.display_primary_white"
+  }
+  prop {
+    api_name: "enable_protected_contents"
+    prop_name: "ro.surface_flinger.protected_contents"
+  }
+  prop {
+    api_name: "force_hwc_copy_for_virtual_displays"
+    prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays"
+  }
+  prop {
+    api_name: "has_HDR_display"
+    prop_name: "ro.surface_flinger.has_HDR_display"
+  }
+  prop {
+    api_name: "has_wide_color_display"
+    prop_name: "ro.surface_flinger.has_wide_color_display"
+  }
+  prop {
+    api_name: "max_frame_buffer_acquired_buffers"
+    type: Long
+    prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
+  }
+  prop {
+    api_name: "max_virtual_display_dimension"
+    type: Long
+    prop_name: "ro.surface_flinger.max_virtual_display_dimension"
+  }
+  prop {
+    api_name: "present_time_offset_from_vsync_ns"
+    type: Long
+    prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns"
+  }
+  prop {
+    api_name: "primary_display_orientation"
+    type: Enum
+    prop_name: "ro.surface_flinger.primary_display_orientation"
+    enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270"
+  }
+  prop {
+    api_name: "running_without_sync_framework"
+    prop_name: "ro.surface_flinger.running_without_sync_framework"
+  }
+  prop {
+    api_name: "set_display_power_timer_ms"
+    type: Integer
+    prop_name: "ro.surface_flinger.set_display_power_timer_ms"
+  }
+  prop {
+    api_name: "set_idle_timer_ms"
+    type: Integer
+    prop_name: "ro.surface_flinger.set_idle_timer_ms"
+  }
+  prop {
+    api_name: "set_touch_timer_ms"
+    type: Integer
+    prop_name: "ro.surface_flinger.set_touch_timer_ms"
+  }
+  prop {
+    api_name: "start_graphics_allocator_service"
+    prop_name: "ro.surface_flinger.start_graphics_allocator_service"
+  }
+  prop {
+    api_name: "support_kernel_idle_timer"
+    prop_name: "ro.surface_flinger.support_kernel_idle_timer"
+  }
+  prop {
+    api_name: "use_color_management"
+    prop_name: "ro.surface_flinger.use_color_management"
+  }
+  prop {
+    api_name: "use_context_priority"
+    prop_name: "ro.surface_flinger.use_context_priority"
+  }
+  prop {
+    api_name: "use_smart_90_for_video"
+    prop_name: "ro.surface_flinger.use_smart_90_for_video"
+  }
+  prop {
+    api_name: "use_vr_flinger"
+    prop_name: "ro.surface_flinger.use_vr_flinger"
+  }
+  prop {
+    api_name: "vsync_event_phase_offset_ns"
+    type: Long
+    prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns"
+  }
+  prop {
+    api_name: "vsync_sf_event_phase_offset_ns"
+    type: Long
+    prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns"
+  }
+  prop {
+    api_name: "wcg_composition_dataspace"
+    type: Long
+    prop_name: "ro.surface_flinger.wcg_composition_dataspace"
+  }
+  prop {
+    api_name: "wcg_composition_pixel_format"
+    type: Integer
+    prop_name: "ro.surface_flinger.wcg_composition_pixel_format"
+  }
+}
diff --git a/services/surfaceflinger/sysprop/api/current.txt b/services/surfaceflinger/sysprop/api/current.txt
deleted file mode 100644
index d802177..0000000
--- a/services/surfaceflinger/sysprop/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/removed.txt b/services/surfaceflinger/sysprop/api/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/services/surfaceflinger/sysprop/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/system-current.txt b/services/surfaceflinger/sysprop/api/system-current.txt
deleted file mode 100644
index 79854b3..0000000
--- a/services/surfaceflinger/sysprop/api/system-current.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-// Signature format: 2.0
-package android.sysprop {
-
-  public final class SurfaceFlingerProperties {
-    method public static java.util.Optional<java.lang.Long> color_space_agnostic_dataspace();
-    method public static java.util.Optional<java.lang.Long> default_composition_dataspace();
-    method public static java.util.Optional<java.lang.Integer> default_composition_pixel_format();
-    method public static java.util.List<java.lang.Double> display_primary_blue();
-    method public static java.util.List<java.lang.Double> display_primary_green();
-    method public static java.util.List<java.lang.Double> display_primary_red();
-    method public static java.util.List<java.lang.Double> display_primary_white();
-    method public static java.util.Optional<java.lang.Boolean> enable_protected_contents();
-    method public static java.util.Optional<java.lang.Boolean> force_hwc_copy_for_virtual_displays();
-    method public static java.util.Optional<java.lang.Boolean> has_HDR_display();
-    method public static java.util.Optional<java.lang.Boolean> has_wide_color_display();
-    method public static java.util.Optional<java.lang.Long> max_frame_buffer_acquired_buffers();
-    method public static java.util.Optional<java.lang.Long> max_virtual_display_dimension();
-    method public static java.util.Optional<java.lang.Long> present_time_offset_from_vsync_ns();
-    method public static java.util.Optional<android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values> primary_display_orientation();
-    method public static java.util.Optional<java.lang.Boolean> running_without_sync_framework();
-    method public static java.util.Optional<java.lang.Integer> set_display_power_timer_ms();
-    method public static java.util.Optional<java.lang.Integer> set_idle_timer_ms();
-    method public static java.util.Optional<java.lang.Integer> set_touch_timer_ms();
-    method public static java.util.Optional<java.lang.Boolean> start_graphics_allocator_service();
-    method public static java.util.Optional<java.lang.Boolean> support_kernel_idle_timer();
-    method public static java.util.Optional<java.lang.Boolean> use_color_management();
-    method public static java.util.Optional<java.lang.Boolean> use_context_priority();
-    method public static java.util.Optional<java.lang.Boolean> use_smart_90_for_video();
-    method public static java.util.Optional<java.lang.Boolean> use_vr_flinger();
-    method public static java.util.Optional<java.lang.Long> vsync_event_phase_offset_ns();
-    method public static java.util.Optional<java.lang.Long> vsync_sf_event_phase_offset_ns();
-    method public static java.util.Optional<java.lang.Long> wcg_composition_dataspace();
-    method public static java.util.Optional<java.lang.Integer> wcg_composition_pixel_format();
-  }
-
-  public enum SurfaceFlingerProperties.primary_display_orientation_values {
-    method public String getPropValue();
-    enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_0;
-    enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_180;
-    enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_270;
-    enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_90;
-  }
-
-}
-
diff --git a/services/surfaceflinger/sysprop/api/system-removed.txt b/services/surfaceflinger/sysprop/api/system-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/services/surfaceflinger/sysprop/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/test-current.txt b/services/surfaceflinger/sysprop/api/test-current.txt
deleted file mode 100644
index d802177..0000000
--- a/services/surfaceflinger/sysprop/api/test-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/test-removed.txt b/services/surfaceflinger/sysprop/api/test-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/services/surfaceflinger/sysprop/api/test-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 47243a9..82dd3c7 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -34,7 +34,6 @@
 #include "ColorLayer.h"
 #include "Layer.h"
 
-#include "TestableScheduler.h"
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
 #include "mock/MockDispSync.h"
@@ -95,10 +94,6 @@
         mFlinger.mutableEventQueue().reset(mMessageQueue);
         setupScheduler();
 
-        EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
-        EXPECT_CALL(*mPrimaryDispSync, getPeriod())
-                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
-        EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
         EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
                 .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
         EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
@@ -125,15 +120,22 @@
     }
 
     void setupScheduler() {
-        mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs());
-        mScheduler->mutableEventControlThread().reset(mEventControlThread);
-        mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
-        EXPECT_CALL(*mEventThread.get(), registerDisplayEventConnection(_));
-        sp<Scheduler::ConnectionHandle> connectionHandle =
-                mScheduler->addConnection(std::move(mEventThread));
-        mFlinger.mutableSfConnectionHandle() = std::move(connectionHandle);
+        auto eventThread = std::make_unique<mock::EventThread>();
+        auto sfEventThread = std::make_unique<mock::EventThread>();
 
-        mFlinger.mutableScheduler().reset(mScheduler);
+        EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+
+        auto primaryDispSync = std::make_unique<mock::DispSync>();
+
+        EXPECT_CALL(*primaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
+        EXPECT_CALL(*primaryDispSync, getPeriod())
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+        EXPECT_CALL(*primaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
+
+        mFlinger.setupScheduler(std::move(primaryDispSync),
+                                std::make_unique<mock::EventControlThread>(),
+                                std::move(eventThread), std::move(sfEventThread));
     }
 
     void setupForceGeometryDirty() {
@@ -157,7 +159,6 @@
 
     std::unordered_set<HWC2::Capability> mDefaultCapabilities = {HWC2::Capability::SidebandStream};
 
-    TestableScheduler* mScheduler;
     TestableSurfaceFlinger mFlinger;
     sp<DisplayDevice> mDisplay;
     sp<DisplayDevice> mExternalDisplay;
@@ -168,13 +169,9 @@
     sp<GraphicBuffer> mBuffer = new GraphicBuffer();
     ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
 
-    std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>();
-    mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
-
     Hwc2::mock::Composer* mComposer = nullptr;
     renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
     mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
-    mock::DispSync* mPrimaryDispSync = new mock::DispSync();
 
     sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
 
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 5f58e7d..8f6f3ec 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -95,11 +95,10 @@
     DisplayTransactionTest();
     ~DisplayTransactionTest() override;
 
-    void setupScheduler();
-
     // --------------------------------------------------------------------
     // Mock/Fake injection
 
+    void injectMockScheduler();
     void injectMockComposer(int virtualDisplayCount);
     void injectFakeBufferQueueFactory();
     void injectFakeNativeWindowSurfaceFactory();
@@ -119,11 +118,7 @@
     // --------------------------------------------------------------------
     // Test instances
 
-    TestableScheduler* mScheduler;
     TestableSurfaceFlinger mFlinger;
-    mock::EventThread* mEventThread = new mock::EventThread();
-    mock::EventThread* mSFEventThread = new mock::EventThread();
-    mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
     sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
     sp<GraphicBuffer> mBuffer = new GraphicBuffer();
 
@@ -134,7 +129,11 @@
     Hwc2::mock::Composer* mComposer = nullptr;
     mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
     mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
-    mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+
+    mock::DispSync* mPrimaryDispSync = new mock::DispSync;
+    mock::EventControlThread* mEventControlThread = new mock::EventControlThread;
+    mock::EventThread* mEventThread = new mock::EventThread;
+    mock::EventThread* mSFEventThread = new mock::EventThread;
 
     // These mocks are created only when expected to be created via a factory.
     sp<mock::GraphicBufferConsumer> mConsumer;
@@ -164,7 +163,7 @@
         return nullptr;
     });
 
-    setupScheduler();
+    injectMockScheduler();
     mFlinger.mutableEventQueue().reset(mMessageQueue);
     mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
     mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
@@ -178,20 +177,14 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-void DisplayTransactionTest::setupScheduler() {
-    mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs());
-    mScheduler->mutableEventControlThread().reset(mEventControlThread);
-    mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
+void DisplayTransactionTest::injectMockScheduler() {
     EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
     EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
 
-    sp<Scheduler::ConnectionHandle> sfConnectionHandle =
-            mScheduler->addConnection(std::unique_ptr<EventThread>(mSFEventThread));
-    mFlinger.mutableSfConnectionHandle() = std::move(sfConnectionHandle);
-    sp<Scheduler::ConnectionHandle> appConnectionHandle =
-            mScheduler->addConnection(std::unique_ptr<EventThread>(mEventThread));
-    mFlinger.mutableAppConnectionHandle() = std::move(appConnectionHandle);
-    mFlinger.mutableScheduler().reset(mScheduler);
+    mFlinger.setupScheduler(std::unique_ptr<DispSync>(mPrimaryDispSync),
+                            std::unique_ptr<EventControlThread>(mEventControlThread),
+                            std::unique_ptr<EventThread>(mEventThread),
+                            std::unique_ptr<EventThread>(mSFEventThread));
 }
 
 void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
@@ -1131,8 +1124,8 @@
     // Preconditions
 
     // vsync is enabled and available
-    mScheduler->mutablePrimaryHWVsyncEnabled() = true;
-    mScheduler->mutableHWVsyncAvailable() = true;
+    mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = true;
+    mFlinger.scheduler()->mutableHWVsyncAvailable() = true;
 
     // A display exists
     auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
@@ -1156,8 +1149,8 @@
     // Postconditions
 
     // vsyncs should be off and not available.
-    EXPECT_FALSE(mScheduler->mutablePrimaryHWVsyncEnabled());
-    EXPECT_FALSE(mScheduler->mutableHWVsyncAvailable());
+    EXPECT_FALSE(mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled());
+    EXPECT_FALSE(mFlinger.scheduler()->mutableHWVsyncAvailable());
 
     // The display should have been removed from the display map.
     EXPECT_FALSE(hasDisplayDevice(existing.token()));
@@ -3008,7 +3001,7 @@
     }
 
     static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) {
-        test->mScheduler->mutablePrimaryHWVsyncEnabled() = enabled;
+        test->mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = enabled;
     }
 
     static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index cb6980e..5157cc4 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -20,15 +20,16 @@
 #include <gui/ISurfaceComposer.h>
 
 #include "Scheduler/EventThread.h"
-#include "Scheduler/RefreshRateConfigs.h"
 #include "Scheduler/Scheduler.h"
 
 namespace android {
 
 class TestableScheduler : public Scheduler {
 public:
-    TestableScheduler(const scheduler::RefreshRateConfigs& refreshRateConfig)
-          : Scheduler([](bool) {}, refreshRateConfig) {}
+    TestableScheduler(std::unique_ptr<DispSync> primaryDispSync,
+                      std::unique_ptr<EventControlThread> eventControlThread,
+                      const scheduler::RefreshRateConfigs& configs)
+          : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs) {}
 
     // Creates EventThreadConnection with the given eventThread. Creates Scheduler::Connection
     // and adds it to the list of connectins. Returns the ConnectionHandle for the
@@ -62,7 +63,7 @@
         mutableEventControlThread().reset();
         mutablePrimaryDispSync().reset();
         mConnections.clear();
-    };
+    }
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 64d34ee..27a119b 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -36,7 +36,7 @@
 #include "SurfaceFlinger.h"
 #include "SurfaceFlingerFactory.h"
 #include "SurfaceInterceptor.h"
-
+#include "TestableScheduler.h"
 #include "TimeStats/TimeStats.h"
 
 namespace android {
@@ -176,6 +176,8 @@
 
 class TestableSurfaceFlinger {
 public:
+    TestableScheduler* scheduler() { return mScheduler; }
+
     // Extend this as needed for accessing SurfaceFlinger private (and public)
     // functions.
 
@@ -188,6 +190,23 @@
                 std::make_unique<impl::HWComposer>(std::move(composer)));
     }
 
+    void setupScheduler(std::unique_ptr<DispSync> primaryDispSync,
+                        std::unique_ptr<EventControlThread> eventControlThread,
+                        std::unique_ptr<EventThread> appEventThread,
+                        std::unique_ptr<EventThread> sfEventThread) {
+        mScheduler =
+                new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread),
+                                      mFlinger->mRefreshRateConfigs);
+
+        mFlinger->mAppConnectionHandle = mScheduler->addConnection(std::move(appEventThread));
+        mFlinger->mSfConnectionHandle = mScheduler->addConnection(std::move(sfEventThread));
+
+        mFlinger->mScheduler.reset(mScheduler);
+        mFlinger->mVSyncModulator.emplace(*mScheduler, mFlinger->mAppConnectionHandle,
+                                          mFlinger->mSfConnectionHandle,
+                                          mFlinger->mPhaseOffsets->getCurrentOffsets());
+    }
+
     using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
     void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
         mFactory.mCreateBufferQueue = f;
@@ -338,10 +357,6 @@
     auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
     auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; }
     auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; }
-    auto& mutableScheduler() { return mFlinger->mScheduler; }
-    auto& mutableAppConnectionHandle() { return mFlinger->mAppConnectionHandle; }
-    auto& mutableSfConnectionHandle() { return mFlinger->mSfConnectionHandle; }
-    auto& mutableRefreshRateConfigs() { return mFlinger->mRefreshRateConfigs; }
 
     ~TestableSurfaceFlinger() {
         // All these pointer and container clears help ensure that GMock does
@@ -353,7 +368,7 @@
         mutableDrawingState().displays.clear();
         mutableEventQueue().reset();
         mutableInterceptor().reset();
-        mutableScheduler().reset();
+        mFlinger->mScheduler.reset();
         mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
         mFlinger->mCompositionEngine->setRenderEngine(
                 std::unique_ptr<renderengine::RenderEngine>());
@@ -573,6 +588,7 @@
 
     surfaceflinger::test::Factory mFactory;
     sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
+    TestableScheduler* mScheduler = nullptr;
 
     // We need to keep a reference to these so they are properly destroyed.
     std::vector<std::unique_ptr<HWC2Display>> mFakeHwcDisplays;
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 368130d..4608be2 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -1172,11 +1172,16 @@
 
     std::call_once(once_flag, []() {
         if (driver::OpenHAL()) {
-            DiscoverLayers();
             initialized = true;
         }
     });
 
+    {
+        static std::mutex layer_lock;
+        std::lock_guard<std::mutex> lock(layer_lock);
+        DiscoverLayers();
+    }
+
     return initialized;
 }