Merge "Merge metadata from transaction instead of replace"
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index bb089e6..768cb4f 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -44,17 +44,18 @@
     return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
 }
 
-static binder::Status error(uint32_t code, const std::string& msg) {
-    MYLOGE("%s (%d) ", msg.c_str(), code);
-    return binder::Status::fromServiceSpecificError(code, String8(msg.c_str()));
-}
-
-// Takes ownership of data.
-static void* callAndNotify(void* data) {
+// Creates a bugreport and exits, thus preserving the oneshot nature of the service.
+// Note: takes ownership of data.
+[[noreturn]] static void* dumpstate_thread_main(void* data) {
     std::unique_ptr<DumpstateInfo> ds_info(static_cast<DumpstateInfo*>(data));
     ds_info->ds->Run(ds_info->calling_uid, ds_info->calling_package);
-    MYLOGD("Finished Run()\n");
-    return nullptr;
+    MYLOGD("Finished taking a bugreport. Exiting.\n");
+    exit(0);
+}
+
+[[noreturn]] static void signalErrorAndExit(sp<IDumpstateListener> listener, int error_code) {
+    listener->onError(error_code);
+    exit(0);
 }
 
 class DumpstateToken : public BnDumpstateToken {};
@@ -120,6 +121,25 @@
                                                 const sp<IDumpstateListener>& listener) {
     MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
 
+    // This is the bugreporting API flow, so ensure there is only one bugreport in progress at a
+    // time.
+    std::lock_guard<std::mutex> lock(lock_);
+    if (ds_ != nullptr) {
+        MYLOGE("Error! There is already a bugreport in progress. Returning.");
+        if (listener != nullptr) {
+            listener->onError(IDumpstateListener::BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN);
+        }
+        return exception(binder::Status::EX_SERVICE_SPECIFIC,
+                         "There is already a bugreport in progress");
+    }
+
+    // From here on, all conditions that indicate we are done with this incoming request should
+    // result in exiting the service to free it up for next invocation.
+    if (listener == nullptr) {
+        MYLOGE("Invalid input: no listener");
+        exit(0);
+    }
+
     if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL &&
         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE &&
         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_REMOTE &&
@@ -127,30 +147,23 @@
         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_TELEPHONY &&
         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WIFI &&
         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_DEFAULT) {
-        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
-                         StringPrintf("Invalid bugreport mode: %d", bugreport_mode));
+        MYLOGE("Invalid input: bad bugreport mode: %d", bugreport_mode);
+        signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
     }
 
     if (bugreport_fd.get() == -1 || screenshot_fd.get() == -1) {
-        return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Invalid file descriptor");
+        // TODO(b/111441001): screenshot fd should be optional
+        MYLOGE("Invalid filedescriptor");
+        signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
     }
 
     std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
     options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd,
                         screenshot_fd);
 
-    // This is the bugreporting API flow, so ensure there is only one bugreport in progress at a
-    // time.
-    std::lock_guard<std::mutex> lock(lock_);
-    if (ds_ != nullptr) {
-        return exception(binder::Status::EX_SERVICE_SPECIFIC,
-                         "There is already a bugreport in progress");
-    }
     ds_ = &(Dumpstate::GetInstance());
     ds_->SetOptions(std::move(options));
-    if (listener != nullptr) {
-        ds_->listener_ = listener;
-    }
+    ds_->listener_ = listener;
 
     DumpstateInfo* ds_info = new DumpstateInfo();
     ds_info->ds = ds_;
@@ -158,11 +171,12 @@
     ds_info->calling_package = calling_package;
 
     pthread_t thread;
-    status_t err = pthread_create(&thread, nullptr, callAndNotify, ds_info);
+    status_t err = pthread_create(&thread, nullptr, dumpstate_thread_main, ds_info);
     if (err != 0) {
         delete ds_info;
         ds_info = nullptr;
-        return error(err, "Could not create a background thread.");
+        MYLOGE("Could not create a thread");
+        signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
     }
     return binder::Status::ok();
 }
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index 273a5a6..c818c05 100644
--- a/cmds/dumpstate/README.md
+++ b/cmds/dumpstate/README.md
@@ -14,7 +14,8 @@
 mmm -j frameworks/native/cmds/dumpstate
 ```
 
-If you're working on device-specific code, you might need to build them as well. Example:
+If you're working on device-specific code, you might need to build them as well.
+Example:
 
 ```
 mmm -j frameworks/native/cmds/dumpstate device/acme/secret_device/dumpstate/ hardware/interfaces/dumpstate
@@ -23,20 +24,23 @@
 ## To build, deploy, and take a bugreport
 
 ```
-mmm -j frameworks/native/cmds/dumpstate && adb push ${OUT}/system/bin/dumpstate system/bin && adb shell am bug-report
+mmm -j frameworks/native/cmds/dumpstate && adb push ${OUT}/system/bin/dumpstate system/bin && adb push ${OUT}/system/lib64/*dumpstate*.so /system/lib64/ && adb shell am bug-report
 ```
 
-Make sure that the device is remounted before running the above command.
-* If you're working with `userdebug` variant, you may need to run the following to remount your device:
+Make sure that the device is remounted before running the above command. * If
+you're working with `userdebug` variant, you may need to run the following to
+remount your device:
 
-  ```
+```
   adb root && adb remount -R && adb wait-for-device && adb root && adb remount
-  ```
-* If you're working with `eng` variant, you may need to run the following to remount your device:
+```
 
-  ```
-  adb root && adb remount
-  ```
+*   If you're working with `eng` variant, you may need to run the following to
+    remount your device:
+
+    ```
+    adb root && adb remount
+    ```
 
 ## To build, deploy, and run unit tests
 
@@ -82,7 +86,6 @@
 adb shell setprop dumpstate.version split-dumpsys && adb shell dumpstate -v
 ```
 
-
 Then to restore the default version:
 
 ```
@@ -91,8 +94,9 @@
 
 ## Code style and formatting
 
-Use the style defined at the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)
-and make sure to run the following command prior to `repo upload`:
+Use the style defined at the
+[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) and
+make sure to run the following command prior to `repo upload`:
 
 ```
 git clang-format --style=file HEAD~
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index b1005d3..37ff442 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -36,6 +36,9 @@
     IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener,
                                 boolean getSectionDetails);
 
+    // NOTE: If you add to or change these modes, please also change the corresponding enums
+    // in system server, in BugreportParams.java.
+
     // These modes encapsulate a set of run time options for generating bugreports.
     // Takes a bugreport without user interference.
     const int BUGREPORT_MODE_FULL = 0;
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 907a67c..42858e0 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -19,6 +19,11 @@
 /**
   * Listener for dumpstate events.
   *
+  * <p>When bugreport creation is complete one of {@code onError} or {@code onFinished} is called.
+  *
+  * <p>These methods are synchronous by design in order to make dumpstate's lifecycle simpler
+  * to handle.
+  *
   * {@hide}
   */
 interface IDumpstateListener {
@@ -27,7 +32,10 @@
      *
      * @param progress the progress in [0, 100]
      */
-    oneway void onProgress(int progress);
+    void onProgress(int progress);
+
+    // NOTE: If you add to or change these error codes, please also change the corresponding enums
+    // in system server, in BugreportManager.java.
 
     /* Options specified are invalid or incompatible */
     const int BUGREPORT_ERROR_INVALID_INPUT = 1;
@@ -41,15 +49,18 @@
     /* The request to get user consent timed out */
     const int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4;
 
+    /* There is currently a bugreport running. The caller should try again later. */
+    const int BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN = 5;
+
     /**
      * Called on an error condition with one of the error codes listed above.
      */
-    oneway void onError(int errorCode);
+    void onError(int errorCode);
 
     /**
      * Called when taking bugreport finishes successfully.
      */
-     oneway void onFinished();
+    void onFinished();
 
     // TODO(b/111441001): Remove old methods when not used anymore.
     void onProgressUpdated(int progress);
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index db8848a..60a7de2 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -113,6 +113,7 @@
 #define LOGPERSIST_DATA_DIR "/data/misc/logd"
 #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
 #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
+#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
 #define WLUTIL "/vendor/xbin/wlutil"
 #define WMTRACE_DATA_DIR "/data/misc/wmtrace"
 
@@ -157,7 +158,7 @@
 }
 
 static bool CopyFileToFd(const std::string& input_file, int out_fd) {
-    MYLOGD("Going to copy bugreport file (%s) to %d\n", ds.path_.c_str(), out_fd);
+    MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
 
     // Obtain a handle to the source file.
     android::base::unique_fd in_fd(OpenForRead(input_file));
@@ -165,14 +166,14 @@
         if (CopyFile(in_fd.get(), out_fd)) {
             return true;
         }
-        MYLOGE("Failed to copy zip file: %s\n", strerror(errno));
+        MYLOGE("Failed to copy file: %s\n", strerror(errno));
     }
     return false;
 }
 
 static bool UnlinkAndLogOnError(const std::string& file) {
-    if (unlink(file.c_str()) != -1) {
-        MYLOGE("Failed to remove file (%s): %s\n", file.c_str(), strerror(errno));
+    if (unlink(file.c_str())) {
+        MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
         return false;
     }
     return true;
@@ -460,9 +461,7 @@
             if (!ds.AddZipEntry("anrd_trace.txt", path)) {
                 MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
             } else {
-                if (remove(path)) {
-                    MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
-                }
+                android::os::UnlinkAndLogOnError(path);
                 return true;
             }
         } else {
@@ -1330,6 +1329,7 @@
     DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
     DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
 
+    RunDumpsys("WINSCOPE TRACE", {"window", "trace"});
     /* Add window and surface trace files. */
     if (!PropertiesHelper::IsUserBuild()) {
         ds.AddDir(WMTRACE_DATA_DIR, false);
@@ -1455,15 +1455,24 @@
     add_mountinfo();
     DumpIpTablesAsRoot();
 
-    // Capture any IPSec policies in play.  No keys are exposed here.
+    // Capture any IPSec policies in play. No keys are exposed here.
     RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
 
+    // Dump IPsec stats. No keys are exposed here.
+    DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
+
     // Run ss as root so we can see socket marks.
     RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
 
     // Run iotop as root to show top 100 IO threads
     RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
 
+    // Gather shared memory buffer info if the product implements it
+    struct stat st;
+    if (!stat("/product/bin/dmabuf_dump", &st)) {
+        RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
+    }
+
     if (!DropRootUser()) {
         return false;
     }
@@ -1582,13 +1591,8 @@
     for (int i = 0; i < NUM_OF_DUMPS; i++) {
         paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
                                         kDumpstateBoardFiles[i].c_str()));
-        remover.emplace_back(android::base::make_scope_guard(std::bind(
-            [](std::string path) {
-                if (remove(path.c_str()) != 0 && errno != ENOENT) {
-                    MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
-                }
-            },
-            paths[i])));
+        remover.emplace_back(android::base::make_scope_guard(
+            std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
     }
 
     sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
@@ -1749,9 +1753,7 @@
     ds.zip_file.reset(nullptr);
 
     MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
-    if (remove(tmp_path_.c_str()) != 0) {
-        MYLOGE("Failed to remove temporary file (%s): %s\n", tmp_path_.c_str(), strerror(errno));
-    }
+    android::os::UnlinkAndLogOnError(tmp_path_);
 
     return true;
 }
@@ -2335,6 +2337,7 @@
 
     register_sig_handler();
 
+    // TODO(b/111441001): maybe skip if already started?
     if (options_->do_start_service) {
         MYLOGI("Starting 'dumpstate' service\n");
         android::status_t ret;
@@ -2481,15 +2484,24 @@
             // Do an early return if there were errors. We make an exception for consent
             // timing out because it's possible the user got distracted. In this case the
             // bugreport is not shared but made available for manual retrieval.
+            MYLOGI("User denied consent. Returning\n");
             return status;
         }
-        if (options_->screenshot_fd.get() != -1) {
+        if (options_->do_fb && options_->screenshot_fd.get() != -1) {
             bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
                                                             options_->screenshot_fd.get());
             if (copy_succeeded) {
                 android::os::UnlinkAndLogOnError(screenshot_path_);
             }
         }
+        if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
+            MYLOGI(
+                "Did not receive user consent yet."
+                " Will not copy the bugreport artifacts to caller.\n");
+            // TODO(b/111441001):
+            // 1. cancel outstanding requests
+            // 2. check for result more frequently
+        }
     }
 
     /* vibrate a few but shortly times to let user know it's finished */
@@ -2592,21 +2604,26 @@
     return Dumpstate::RunStatus::ERROR;
 }
 
-/* Main entry point for dumpstate binary. */
-int run_main(int argc, char* argv[]) {
+Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
     std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
     Dumpstate::RunStatus status = options->Initialize(argc, argv);
     if (status == Dumpstate::RunStatus::OK) {
-        ds.SetOptions(std::move(options));
+        SetOptions(std::move(options));
         // When directly running dumpstate binary, the output is not expected to be written
         // to any external file descriptor.
-        assert(ds.options_->bugreport_fd.get() == -1);
+        assert(options_->bugreport_fd.get() == -1);
 
         // calling_uid and calling_package are for user consent to share the bugreport with
         // an app; they are irrelvant here because bugreport is only written to a local
         // directory, and not shared.
-        status = ds.Run(-1 /* calling_uid */, "" /* calling_package */);
+        status = Run(-1 /* calling_uid */, "" /* calling_package */);
     }
+    return status;
+}
+
+/* Main entry point for dumpstate binary. */
+int run_main(int argc, char* argv[]) {
+    Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
 
     switch (status) {
         case Dumpstate::RunStatus::OK:
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 7fb2f3b..9803f00 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -322,6 +322,8 @@
     /* Main entry point for running a complete bugreport. */
     RunStatus Run(int32_t calling_uid, const std::string& calling_package);
 
+    RunStatus ParseCommandlineAndRun(int argc, char* argv[]);
+
     /* Sets runtime options. */
     void SetOptions(std::unique_ptr<DumpOptions> options);
 
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 570c6c9..555badd 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -21,6 +21,10 @@
 #include <libgen.h>
 
 #include <android-base/file.h>
+#include <android/os/BnDumpstate.h>
+#include <android/os/BnDumpstateListener.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 #include <cutils/properties.h>
 #include <ziparchive/zip_archive.h>
 
@@ -34,6 +38,24 @@
 
 using ::testing::Test;
 using ::std::literals::chrono_literals::operator""s;
+using android::base::unique_fd;
+
+class DumpstateListener;
+
+namespace {
+
+sp<IDumpstate> GetDumpstateService() {
+    return android::interface_cast<IDumpstate>(
+        android::defaultServiceManager()->getService(String16("dumpstate")));
+}
+
+int OpenForWrite(const std::string& filename) {
+    return TEMP_FAILURE_RETRY(open(filename.c_str(),
+                                   O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
+}
+
+}  // namespace
 
 struct SectionInfo {
     std::string name;
@@ -46,41 +68,71 @@
  * Listens to bugreport progress and updates the user by writing the progress to STDOUT. All the
  * section details generated by dumpstate are added to a vector to be used by Tests later.
  */
-class DumpstateListener : public IDumpstateListener {
+class DumpstateListener : public BnDumpstateListener {
   public:
-    int outFd_, max_progress_;
-    std::shared_ptr<std::vector<SectionInfo>> sections_;
     DumpstateListener(int fd, std::shared_ptr<std::vector<SectionInfo>> sections)
-        : outFd_(fd), max_progress_(5000), sections_(sections) {
+        : out_fd_(fd), sections_(sections) {
     }
+
+    DumpstateListener(int fd) : out_fd_(fd) {
+    }
+
     binder::Status onProgress(int32_t progress) override {
-        dprintf(outFd_, "\rIn progress %d", progress);
+        dprintf(out_fd_, "\rIn progress %d", progress);
         return binder::Status::ok();
     }
+
     binder::Status onError(int32_t error_code) override {
-        dprintf(outFd_, "\rError %d", error_code);
+        std::lock_guard<std::mutex> lock(lock_);
+        error_code_ = error_code;
+        dprintf(out_fd_, "\rError code %d", error_code);
         return binder::Status::ok();
     }
+
     binder::Status onFinished() override {
-        dprintf(outFd_, "\rFinished");
+        std::lock_guard<std::mutex> lock(lock_);
+        is_finished_ = true;
+        dprintf(out_fd_, "\rFinished");
         return binder::Status::ok();
     }
+
     binder::Status onProgressUpdated(int32_t progress) override {
-        dprintf(outFd_, "\rIn progress %d/%d", progress, max_progress_);
+        dprintf(out_fd_, "\rIn progress %d/%d", progress, max_progress_);
         return binder::Status::ok();
     }
+
     binder::Status onMaxProgressUpdated(int32_t max_progress) override {
+        std::lock_guard<std::mutex> lock(lock_);
         max_progress_ = max_progress;
         return binder::Status::ok();
     }
+
     binder::Status onSectionComplete(const ::std::string& name, int32_t status, int32_t size_bytes,
                                      int32_t duration_ms) override {
-        sections_->push_back({name, status, size_bytes, duration_ms});
+        std::lock_guard<std::mutex> lock(lock_);
+        if (sections_.get() != nullptr) {
+            sections_->push_back({name, status, size_bytes, duration_ms});
+        }
         return binder::Status::ok();
     }
-    IBinder* onAsBinder() override {
-        return nullptr;
+
+    bool getIsFinished() {
+        std::lock_guard<std::mutex> lock(lock_);
+        return is_finished_;
     }
+
+    int getErrorCode() {
+        std::lock_guard<std::mutex> lock(lock_);
+        return error_code_;
+    }
+
+  private:
+    int out_fd_;
+    int max_progress_ = 5000;
+    int error_code_ = -1;
+    bool is_finished_ = false;
+    std::shared_ptr<std::vector<SectionInfo>> sections_;
+    std::mutex lock_;
 };
 
 /**
@@ -109,7 +161,7 @@
         ds.listener_name_ = "Smokey";
         ds.report_section_ = true;
         auto start = std::chrono::steady_clock::now();
-        run_main(ARRAY_SIZE(argv), argv);
+        ds.ParseCommandlineAndRun(ARRAY_SIZE(argv), argv);
         auto end = std::chrono::steady_clock::now();
         duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
     }
@@ -293,6 +345,148 @@
     SectionExists("DUMPSYS - wifi", /* bytes= */ 100000);
 }
 
+class DumpstateBinderTest : public Test {
+  protected:
+    void SetUp() override {
+        // In case there is a stray service, stop it first.
+        property_set("ctl.stop", "bugreportd");
+        // dry_run results in a faster bugreport.
+        property_set("dumpstate.dry_run", "true");
+        // We need to receive some async calls later. Ensure we have binder threads.
+        ProcessState::self()->startThreadPool();
+    }
+
+    void TearDown() override {
+        property_set("ctl.stop", "bugreportd");
+        property_set("dumpstate.dry_run", "");
+
+        unlink("/data/local/tmp/tmp.zip");
+        unlink("/data/local/tmp/tmp.png");
+    }
+
+    // Waits until listener gets the callbacks.
+    void WaitTillExecutionComplete(DumpstateListener* listener) {
+        // Wait till one of finished, error or timeout.
+        static const int kBugreportTimeoutSeconds = 120;
+        int i = 0;
+        while (!listener->getIsFinished() && listener->getErrorCode() == -1 &&
+               i < kBugreportTimeoutSeconds) {
+            sleep(1);
+            i++;
+        }
+    }
+};
+
+TEST_F(DumpstateBinderTest, Baseline) {
+    // In the beginning dumpstate binder service is not running.
+    sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
+    EXPECT_EQ(ds_binder, nullptr);
+
+    // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
+    // and makes it wait.
+    property_set("dumpstate.dry_run", "true");
+    property_set("ctl.start", "bugreportd");
+
+    // Now we are able to retrieve dumpstate binder service.
+    ds_binder = GetDumpstateService();
+    EXPECT_NE(ds_binder, nullptr);
+
+    // Prepare arguments
+    unique_fd bugreport_fd(OpenForWrite("/bugreports/tmp.zip"));
+    unique_fd screenshot_fd(OpenForWrite("/bugreports/tmp.png"));
+
+    EXPECT_NE(bugreport_fd.get(), -1);
+    EXPECT_NE(screenshot_fd.get(), -1);
+
+    sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
+    android::binder::Status status =
+        ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+                                  Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener);
+    // startBugreport is an async call. Verify binder call succeeded first, then wait till listener
+    // gets expected callbacks.
+    EXPECT_TRUE(status.isOk());
+    WaitTillExecutionComplete(listener.get());
+
+    // Bugreport generation requires user consent, which we cannot get in a test set up,
+    // so instead of getting is_finished_, we are more likely to get a consent error.
+    EXPECT_TRUE(
+        listener->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT ||
+        listener->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+
+    // The service should have died on its own, freeing itself up for a new invocation.
+    sleep(2);
+    ds_binder = GetDumpstateService();
+    EXPECT_EQ(ds_binder, nullptr);
+}
+
+TEST_F(DumpstateBinderTest, ServiceDies_OnInvalidInput) {
+    // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
+    // and makes it wait.
+    property_set("ctl.start", "bugreportd");
+    sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
+    EXPECT_NE(ds_binder, nullptr);
+
+    // Prepare arguments
+    unique_fd bugreport_fd(OpenForWrite("/data/local/tmp/tmp.zip"));
+    unique_fd screenshot_fd(OpenForWrite("/data/local/tmp/tmp.png"));
+
+    EXPECT_NE(bugreport_fd.get(), -1);
+    EXPECT_NE(screenshot_fd.get(), -1);
+
+    // Call startBugreport with bad arguments.
+    sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
+    android::binder::Status status =
+        ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+                                  2000,  // invalid bugreport mode
+                                  listener);
+    EXPECT_EQ(listener->getErrorCode(), IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
+
+    // The service should have died, freeing itself up for a new invocation.
+    sleep(2);
+    ds_binder = GetDumpstateService();
+    EXPECT_EQ(ds_binder, nullptr);
+}
+
+TEST_F(DumpstateBinderTest, SimultaneousBugreportsNotAllowed) {
+    // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
+    // and makes it wait.
+    property_set("dumpstate.dry_run", "true");
+    property_set("ctl.start", "bugreportd");
+    sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
+    EXPECT_NE(ds_binder, nullptr);
+
+    // Prepare arguments
+    unique_fd bugreport_fd(OpenForWrite("/data/local/tmp/tmp.zip"));
+    unique_fd screenshot_fd(OpenForWrite("/data/local/tmp/tmp.png"));
+
+    EXPECT_NE(bugreport_fd.get(), -1);
+    EXPECT_NE(screenshot_fd.get(), -1);
+
+    sp<DumpstateListener> listener1(new DumpstateListener(dup(fileno(stdout))));
+    android::binder::Status status =
+        ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+                                  Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1);
+    EXPECT_TRUE(status.isOk());
+
+    // try to make another call to startBugreport. This should fail.
+    sp<DumpstateListener> listener2(new DumpstateListener(dup(fileno(stdout))));
+    status = ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+                                       Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2);
+    EXPECT_FALSE(status.isOk());
+    WaitTillExecutionComplete(listener2.get());
+    EXPECT_EQ(listener2->getErrorCode(),
+              IDumpstateListener::BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN);
+
+    // Meanwhile the first call works as expected. Service should not die in this case.
+    WaitTillExecutionComplete(listener1.get());
+
+    // Bugreport generation requires user consent, which we cannot get in a test set up,
+    // so instead of getting is_finished_, we are more likely to get a consent error.
+    EXPECT_TRUE(
+        listener1->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT ||
+        listener1->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+}
+
 }  // namespace dumpstate
 }  // namespace os
 }  // namespace android
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 62d2fa1..d398559 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -222,9 +222,9 @@
 }
 
 bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) {
-    sp<IBinder> dpy = mSurfaceComposerClient->getBuiltInDisplay(0);
+    const sp<IBinder> dpy = mSurfaceComposerClient->getInternalDisplayToken();
     if (dpy == nullptr) {
-        fprintf(stderr, "SurfaceComposer::getBuiltInDisplay failed.\n");
+        fprintf(stderr, "SurfaceComposer::getInternalDisplayToken failed.\n");
         return false;
     }
 
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 49383e5..2efcf11 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -39,6 +39,7 @@
 #include <sys/xattr.h>
 #include <unistd.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/scopeguard.h>
@@ -80,6 +81,8 @@
 // An uuid used in unit tests.
 static constexpr const char* kTestUuid = "TEST";
 
+static constexpr const mode_t kRollbackFolderMode = 0700;
+
 static constexpr const char* kCpPath = "/system/bin/cp";
 static constexpr const char* kXattrDefault = "user.default";
 
@@ -822,8 +825,8 @@
 
 binder::Status InstalldNativeService::snapshotAppData(
         const std::unique_ptr<std::string>& volumeUuid,
-        const std::string& packageName, int32_t user, int32_t storageFlags,
-        int64_t* _aidl_return) {
+        const std::string& packageName, int32_t user, int32_t snapshotId,
+        int32_t storageFlags, int64_t* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -840,16 +843,19 @@
     bool clear_ce_on_exit = false;
     bool clear_de_on_exit = false;
 
-    auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name] {
+    auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name,
+            &snapshotId] {
         if (clear_de_on_exit) {
-            auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, package_name);
+            auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, snapshotId,
+                    package_name);
             if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
                 LOG(WARNING) << "Failed to delete app data snapshot: " << to;
             }
         }
 
         if (clear_ce_on_exit) {
-            auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name);
+            auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshotId,
+                    package_name);
             if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
                 LOG(WARNING) << "Failed to delete app data snapshot: " << to;
             }
@@ -885,15 +891,21 @@
 
     if (storageFlags & FLAG_STORAGE_DE) {
         auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
-        auto to = create_data_misc_de_rollback_path(volume_uuid, user);
+        auto to = create_data_misc_de_rollback_path(volume_uuid, user, snapshotId);
+        auto rollback_package_path = create_data_misc_de_rollback_package_path(volume_uuid, user,
+            snapshotId, package_name);
 
-        int rd = delete_dir_contents(to, true /* ignore_if_missing */);
-        if (rd != 0) {
-            res = error(rd, "Failed clearing existing snapshot " + to);
-            return res;
+        int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
+        if (rc != 0) {
+            return error(rc, "Failed to create folder " + to);
         }
 
-        int rc = copy_directory_recursive(from.c_str(), to.c_str());
+        rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
+        if (rc != 0) {
+            return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
+        }
+
+        rc = copy_directory_recursive(from.c_str(), to.c_str());
         if (rc != 0) {
             res = error(rc, "Failed copying " + from + " to " + to);
             clear_de_on_exit = true;
@@ -903,15 +915,21 @@
 
     if (storageFlags & FLAG_STORAGE_CE) {
         auto from = create_data_user_ce_package_path(volume_uuid, user, package_name);
-        auto to = create_data_misc_ce_rollback_path(volume_uuid, user);
+        auto to = create_data_misc_ce_rollback_path(volume_uuid, user, snapshotId);
+        auto rollback_package_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
+            snapshotId, package_name);
 
-        int rd = delete_dir_contents(to, true /* ignore_if_missing */);
-        if (rd != 0) {
-            res = error(rd, "Failed clearing existing snapshot " + to);
-            return res;
+        int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
+        if (rc != 0) {
+            return error(rc, "Failed to create folder " + to);
         }
 
-        int rc = copy_directory_recursive(from.c_str(), to.c_str());
+        rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
+        if (rc != 0) {
+            return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
+        }
+
+        rc = copy_directory_recursive(from.c_str(), to.c_str());
         if (rc != 0) {
             res = error(rc, "Failed copying " + from + " to " + to);
             clear_ce_on_exit = true;
@@ -919,7 +937,7 @@
         }
         if (_aidl_return != nullptr) {
             auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
-                    package_name);
+                    snapshotId, package_name);
             rc = get_path_inode(ce_snapshot_path, reinterpret_cast<ino_t*>(_aidl_return));
             if (rc != 0) {
                 res = error(rc, "Failed to get_path_inode for " + ce_snapshot_path);
@@ -934,8 +952,8 @@
 
 binder::Status InstalldNativeService::restoreAppDataSnapshot(
         const std::unique_ptr<std::string>& volumeUuid, const std::string& packageName,
-        const int32_t appId, const int64_t ceDataInode, const std::string& seInfo,
-        const int32_t user, int32_t storageFlags) {
+        const int32_t appId, const std::string& seInfo, const int32_t user,
+        const int32_t snapshotId, int32_t storageFlags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -945,9 +963,9 @@
     const char* package_name = packageName.c_str();
 
     auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid,
-            user, package_name);
+            user, snapshotId, package_name);
     auto from_de = create_data_misc_de_rollback_package_path(volume_uuid,
-            user, package_name);
+            user, snapshotId, package_name);
 
     const bool needs_ce_rollback = (storageFlags & FLAG_STORAGE_CE) &&
         (access(from_ce.c_str(), F_OK) == 0);
@@ -964,7 +982,11 @@
     // app with no data in those cases is arguably better than leaving the app
     // with mismatched / stale data.
     LOG(INFO) << "Clearing app data for " << packageName << " to restore snapshot.";
-    binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags, ceDataInode);
+    // It's fine to pass 0 as ceDataInode here, because restoreAppDataSnapshot
+    // can only be called when user unlocks the phone, meaning that CE user data
+    // is decrypted.
+    binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags,
+            0 /* ceDataInode */);
     if (!res.isOk()) {
         return res;
     }
@@ -1000,7 +1022,8 @@
 
 binder::Status InstalldNativeService::destroyAppDataSnapshot(
         const std::unique_ptr<std::string> &volumeUuid, const std::string& packageName,
-        const int32_t user, const int64_t ceSnapshotInode, int32_t storageFlags) {
+        const int32_t user, const int64_t ceSnapshotInode, const int32_t snapshotId,
+        int32_t storageFlags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -1011,7 +1034,7 @@
 
     if (storageFlags & FLAG_STORAGE_DE) {
         auto de_snapshot_path = create_data_misc_de_rollback_package_path(volume_uuid,
-                user, package_name);
+                user, snapshotId, package_name);
 
         int res = delete_dir_contents_and_dir(de_snapshot_path, true /* ignore_if_missing */);
         if (res != 0) {
@@ -1021,7 +1044,7 @@
 
     if (storageFlags & FLAG_STORAGE_CE) {
         auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid,
-                user, package_name, ceSnapshotInode);
+                user, snapshotId, package_name, ceSnapshotInode);
         int res = delete_dir_contents_and_dir(ce_snapshot_path, true /* ignore_if_missing */);
         if (res != 0) {
             return error(res, "Failed clearing snapshot " + ce_snapshot_path);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 578132d..0e91cb2 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -61,14 +61,14 @@
     binder::Status fixupAppData(const std::unique_ptr<std::string>& uuid, int32_t flags);
 
     binder::Status snapshotAppData(const std::unique_ptr<std::string>& volumeUuid,
-            const std::string& packageName, const int32_t user, int32_t storageFlags,
-            int64_t* _aidl_return);
+            const std::string& packageName, const int32_t user, const int32_t snapshotId,
+            int32_t storageFlags, int64_t* _aidl_return);
     binder::Status restoreAppDataSnapshot(const std::unique_ptr<std::string>& volumeUuid,
-            const std::string& packageName, const int32_t appId, const int64_t ceDataInode,
-            const std::string& seInfo, const int32_t user, int32_t storageFlags);
+            const std::string& packageName, const int32_t appId, const std::string& seInfo,
+            const int32_t user, const int32_t snapshotId, int32_t storageFlags);
     binder::Status destroyAppDataSnapshot(const std::unique_ptr<std::string> &volumeUuid,
             const std::string& packageName, const int32_t user, const int64_t ceSnapshotInode,
-            int32_t storageFlags);
+            const int32_t snapshotId, int32_t storageFlags);
 
     binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
             const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index 3de5c79..287f2d9 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -14,6 +14,15 @@
     },
     {
       "name": "installd_utils_test"
+    },
+    {
+      "name": "CtsUsesLibraryHostTestCases"
+    },
+    {
+      "name": "CtsClassloaderSplitsHostTestCases"
+    },
+    {
+      "name": "CtsCompilationTestCases"
     }
   ]
 }
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index b345210..63c9765 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -106,11 +106,11 @@
         @nullable @utf8InCpp String dexMetadata);
 
     long snapshotAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
-            int userId, int storageFlags);
+            int userId, int snapshotId, int storageFlags);
     void restoreAppDataSnapshot(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
-            int appId, long ceDataInode, @utf8InCpp String seInfo, int user, int storageflags);
+            int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
     void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
-            int userId, long ceSnapshotInode, int storageFlags);
+            int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
 
     const int FLAG_STORAGE_DE = 0x1;
     const int FLAG_STORAGE_CE = 0x2;
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index a639951..acc0647 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -352,6 +352,8 @@
         bool generate_minidebug_info = kEnableMinidebugInfo &&
                 GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
 
+        std::string boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
+
         // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
         // use arraysize instead.
         std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
@@ -366,7 +368,7 @@
         std::string dex2oat_image_fd;
         std::string target_sdk_version_arg;
         if (target_sdk_version != 0) {
-            StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
+            target_sdk_version_arg = StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
         }
         std::string class_loader_context_arg;
         if (class_loader_context != nullptr) {
@@ -437,6 +439,7 @@
         AddArg(instruction_set_variant_arg);
         AddArg(instruction_set_features_arg);
 
+        AddRuntimeArg(boot_image);
         AddRuntimeArg(dex2oat_Xms_arg);
         AddRuntimeArg(dex2oat_Xmx_arg);
 
@@ -468,7 +471,7 @@
         if (disable_cdex) {
             AddArg(kDisableCompactDexFlag);
         }
-        AddArg(target_sdk_version_arg);
+        AddRuntimeArg(target_sdk_version_arg);
         if (enable_hidden_api_checks) {
             AddRuntimeArg("-Xhidden-api-checks");
         }
@@ -1958,6 +1961,11 @@
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
 
+        // Clear BOOTCLASSPATH.
+        // Let dex2oat use the BCP from boot image, excluding updatable BCP
+        // modules for AOT to avoid app recompilation after their upgrades.
+        unsetenv("BOOTCLASSPATH");
+
         SetDex2OatScheduling(boot_complete);
         if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
             PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 609ddaf..670abea 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -80,8 +80,6 @@
     // system/apex/apexd/apexd_main.cpp.
     //
     // Only scan the APEX directory under /system (within the chroot dir).
-    // Note that this leaves around the loop devices created and used by
-    // libapexd's code, but this is fine, as we expect to reboot soon after.
     apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir);
     return apex::getActivePackages();
 }
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index cc24ab3..a31d510 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/statvfs.h>
+#include <sys/stat.h>
 #include <sys/xattr.h>
 
 #include <android-base/file.h>
@@ -70,27 +71,28 @@
 
 static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
     const std::string fullPath = get_full_path(path);
-    ::mkdir(fullPath.c_str(), mode);
-    ::chown(fullPath.c_str(), owner, group);
-    ::chmod(fullPath.c_str(), mode);
+    EXPECT_EQ(::mkdir(fullPath.c_str(), mode), 0);
+    EXPECT_EQ(::chown(fullPath.c_str(), owner, group), 0);
+    EXPECT_EQ(::chmod(fullPath.c_str(), mode), 0);
 }
 
 static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
     int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
-    ::fchown(fd, owner, group);
-    ::fchmod(fd, mode);
-    ::close(fd);
+    EXPECT_NE(fd, -1);
+    EXPECT_EQ(::fchown(fd, owner, group), 0);
+    EXPECT_EQ(::fchmod(fd, mode), 0);
+    EXPECT_EQ(::close(fd), 0);
 }
 
 static int stat_gid(const char* path) {
     struct stat buf;
-    ::stat(get_full_path(path).c_str(), &buf);
+    EXPECT_EQ(::stat(get_full_path(path).c_str(), &buf), 0);
     return buf.st_gid;
 }
 
 static int stat_mode(const char* path) {
     struct stat buf;
-    ::stat(get_full_path(path).c_str(), &buf);
+    EXPECT_EQ(::stat(get_full_path(path).c_str(), &buf), 0);
     return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
 }
 
@@ -257,32 +259,59 @@
         return false;
     }
 
-    return (::mkdir(path.c_str(), mode) != -1);
+    if (::mkdir(path.c_str(), mode) != 0) {
+        PLOG(DEBUG) << "Failed to create folder " << path;
+        return false;
+    }
+    return true;
 }
 
-TEST_F(ServiceTest, CreateAppDataSnapshot) {
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+class AppDataSnapshotTest : public testing::Test {
+private:
+    std::string rollback_ce_base_dir;
+    std::string rollback_de_base_dir;
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+protected:
+    InstalldNativeService* service;
 
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+    std::string fake_package_ce_path;
+    std::string fake_package_de_path;
 
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+    virtual void SetUp() {
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
 
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+        service = new InstalldNativeService();
+        ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700));
+
+        init_globals_from_data_and_root();
+
+        rollback_ce_base_dir = create_data_misc_ce_rollback_base_path("TEST", 0);
+        rollback_de_base_dir = create_data_misc_de_rollback_base_path("TEST", 0);
+
+        fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+        fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+        ASSERT_TRUE(mkdirs(rollback_ce_base_dir, 0700));
+        ASSERT_TRUE(mkdirs(rollback_de_base_dir, 0700));
+        ASSERT_TRUE(mkdirs(fake_package_ce_path, 0700));
+        ASSERT_TRUE(mkdirs(fake_package_de_path, 0700));
+    }
+
+    virtual void TearDown() {
+        ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_ce_base_dir, true));
+        ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_de_base_dir, true));
+        ASSERT_EQ(0, delete_dir_contents(fake_package_ce_path, true));
+        ASSERT_EQ(0, delete_dir_contents(fake_package_de_path, true));
+
+        delete service;
+        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user/0", true));
+    }
+};
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 37);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 37);
 
   ASSERT_TRUE(android::base::WriteStringToFile(
           "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
@@ -294,7 +323,7 @@
   // Request a snapshot of the CE content but not the DE content.
   int64_t ce_snapshot_inode;
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode));
+          "com.foo", 0, 37, FLAG_STORAGE_CE, &ce_snapshot_inode));
   struct stat buf;
   memset(&buf, 0, sizeof(buf));
   ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &buf));
@@ -316,7 +345,7 @@
 
   // Request a snapshot of the DE content but not the CE content.
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_DE, &ce_snapshot_inode));
+          "com.foo", 0, 37, FLAG_STORAGE_DE, &ce_snapshot_inode));
   // Only DE content snapshot was requested.
   ASSERT_EQ(ce_snapshot_inode, 0);
 
@@ -337,7 +366,7 @@
 
   // Request a snapshot of both the CE as well as the DE content.
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+          "com.foo", 0, 37, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
 
   ASSERT_TRUE(android::base::ReadFileToString(
       rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
@@ -347,27 +376,73 @@
   ASSERT_EQ("TEST_CONTENT_DE_MODIFIED", de_content);
 }
 
-TEST_F(ServiceTest, CreateAppDataSnapshot_AppDataAbsent) {
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_TwoSnapshotsWithTheSameId) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 67);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 67);
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+  auto another_fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.bar");
+  auto another_fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.bar");
 
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
+  // Since this test sets up data for another package, some bookkeeping is required.
+  auto deleter = [&]() {
+      ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_ce_path, true));
+      ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_de_path, true));
   };
-
   auto scope_guard = android::base::make_scope_guard(deleter);
 
+  ASSERT_TRUE(mkdirs(another_fake_package_ce_path, 0700));
+  ASSERT_TRUE(mkdirs(another_fake_package_de_path, 0700));
+
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "ANOTHER_TEST_CONTENT_CE", another_fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "ANOTHER_TEST_CONTENT_DE", another_fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  // Request snapshot for the package com.foo.
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+  // Now request snapshot with the same id for the package com.bar
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.bar", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+
+  // Check that both snapshots have correct data in them.
+  std::string com_foo_ce_content, com_foo_de_content;
+  std::string com_bar_ce_content, com_bar_de_content;
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_ce_dir + "/com.foo/file1", &com_foo_ce_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_de_dir + "/com.foo/file1", &com_foo_de_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_ce_dir + "/com.bar/file1", &com_bar_ce_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_de_dir + "/com.bar/file1", &com_bar_de_content, false /* follow_symlinks */));
+  ASSERT_EQ("TEST_CONTENT_CE", com_foo_ce_content);
+  ASSERT_EQ("TEST_CONTENT_DE", com_foo_de_content);
+  ASSERT_EQ("ANOTHER_TEST_CONTENT_CE", com_bar_ce_content);
+  ASSERT_EQ("ANOTHER_TEST_CONTENT_DE", com_bar_de_content);
+}
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_AppDataAbsent) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 73);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 73);
+
+  // Similuating app data absence.
+  ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_ce_path, true));
+  ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_de_path, true));
+
   int64_t ce_snapshot_inode;
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode));
+          "com.foo", 0, 73, FLAG_STORAGE_CE, &ce_snapshot_inode));
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_DE, nullptr));
+          "com.foo", 0, 73, FLAG_STORAGE_DE, nullptr));
   // No CE content snapshot was performed.
   ASSERT_EQ(ce_snapshot_inode, 0);
 
@@ -378,29 +453,12 @@
   ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
 }
 
-TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsExistingSnapshot) {
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsExistingSnapshot) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_package_path("TEST", 0, 13, "com.foo");
+  auto rollback_de_dir = create_data_misc_de_rollback_package_path("TEST", 0, 13, "com.foo");
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
   // Simulate presence of an existing snapshot
   ASSERT_TRUE(android::base::WriteStringToFile(
@@ -419,62 +477,40 @@
           0700, 10000, 20000, false /* follow_symlinks */));
 
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+          "com.foo", 0, 13, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
 
   // Previous snapshot (with data for file1) must be cleared.
   struct stat sb;
-  ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo/file1").c_str(), &sb));
-  ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo/file1").c_str(), &sb));
+  ASSERT_EQ(-1, stat((rollback_ce_dir + "/file1").c_str(), &sb));
+  ASSERT_EQ(-1, stat((rollback_de_dir + "/file1").c_str(), &sb));
+  // New snapshot (with data for file2) must be present.
+  ASSERT_NE(-1, stat((rollback_ce_dir + "/file2").c_str(), &sb));
+  ASSERT_NE(-1, stat((rollback_de_dir + "/file2").c_str(), &sb));
 }
 
-TEST_F(ServiceTest, SnapshotAppData_WrongVolumeUuid) {
-  // Setup app data to make sure that fails due to wrong volumeUuid being
+TEST_F(AppDataSnapshotTest, SnapshotAppData_WrongVolumeUuid) {
+  // Setup rollback folders to make sure that fails due to wrong volumeUuid being
   // passed, not because of some other reason.
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 17);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 17);
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
   EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_unique<std::string>("FOO"),
-          "com.foo", 0, FLAG_STORAGE_DE, nullptr));
+          "com.foo", 0, 17, FLAG_STORAGE_DE, nullptr));
 }
 
-TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsCache) {
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsCache) {
   auto fake_package_ce_cache_path = fake_package_ce_path + "/cache";
   auto fake_package_ce_code_cache_path = fake_package_ce_path + "/code_cache";
   auto fake_package_de_cache_path = fake_package_de_path + "/cache";
   auto fake_package_de_code_cache_path = fake_package_de_path + "/code_cache";
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
 
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 700));
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto deleter = [&fake_package_ce_path, &fake_package_de_path,
-          &rollback_ce_dir, &rollback_de_dir]() {
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      delete_dir_contents_and_dir(rollback_ce_dir, true);
-      delete_dir_contents_and_dir(rollback_de_dir, true);
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+  ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 0700));
+  ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 0700));
+  ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 0700));
+  ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 0700));
 
   ASSERT_TRUE(android::base::WriteStringToFile(
           "TEST_CONTENT_CE", fake_package_ce_cache_path + "/file1",
@@ -489,7 +525,7 @@
           "TEST_CONTENT_DE", fake_package_de_code_cache_path + "/file1",
           0700, 10000, 20000, false /* follow_symlinks */));
   ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr));
+          "com.foo", 0, 23, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr));
   // The snapshot call must clear cache.
   struct stat sb;
   ASSERT_EQ(-1, stat((fake_package_ce_cache_path + "/file1").c_str(), &sb));
@@ -498,34 +534,17 @@
   ASSERT_EQ(-1, stat((fake_package_de_code_cache_path + "/file1").c_str(), &sb));
 }
 
-TEST_F(ServiceTest, RestoreAppDataSnapshot) {
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 239);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 239);
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
   // Write contents to the rollback location. We'll write the same files to the
   // app data location and make sure the restore has overwritten them.
-  ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700));
+  ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700));
   ASSERT_TRUE(android::base::WriteStringToFile(
           "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
           0700, 10000, 20000, false /* follow_symlinks */));
@@ -540,7 +559,7 @@
           0700, 10000, 20000, false /* follow_symlinks */));
 
   ASSERT_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_unique<std::string>("TEST"),
-          "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
+          "com.foo", 10000, "", 0, 239, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
 
   std::string ce_content, de_content;
   ASSERT_TRUE(android::base::ReadFileToString(
@@ -551,29 +570,9 @@
   ASSERT_EQ("DE_RESTORE_CONTENT", de_content);
 }
 
-TEST_F(ServiceTest, CreateSnapshotThenDestroyIt) {
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
-
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+TEST_F(AppDataSnapshotTest, CreateSnapshotThenDestroyIt) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 57);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 57);
 
   // Prepare data for snapshot.
   ASSERT_TRUE(android::base::WriteStringToFile(
@@ -586,7 +585,7 @@
   int64_t ce_snapshot_inode;
   // Request a snapshot of both the CE as well as the DE content.
   ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
+          "com.foo", 0, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
   // Because CE data snapshot was requested, ce_snapshot_inode can't be null.
   ASSERT_NE(0, ce_snapshot_inode);
   // Check snapshot is there.
@@ -596,39 +595,19 @@
 
 
   ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, ce_snapshot_inode, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+          "com.foo", 0, ce_snapshot_inode, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
   // Check snapshot is deleted.
   ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
   ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
 }
 
-TEST_F(ServiceTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) {
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
-
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 1543);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 1543);
 
   // Create a snapshot
-  ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700));
+  ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700));
   ASSERT_TRUE(android::base::WriteStringToFile(
           "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
           0700, 10000, 20000, false /* follow_symlinks */));
@@ -637,7 +616,7 @@
           0700, 10000, 20000, false /* follow_symlinks */));
 
   ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+          "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
 
   // Check snapshot is deleted.
   struct stat sb;
@@ -646,67 +625,33 @@
 
   // Check that deleting already deleted snapshot is no-op.
   ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
-          "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+          "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
 }
 
-TEST_F(ServiceTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
+TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
   // Setup rollback data to make sure that test fails due to wrong volumeUuid
   // being passed, not because of some other reason.
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 43);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 43);
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
   ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_unique<std::string>("BAR"),
-          "com.foo", 0, 0, FLAG_STORAGE_DE).isOk());
+          "com.foo", 0, 0, 43, FLAG_STORAGE_DE).isOk());
 }
 
-TEST_F(ServiceTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
+TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
   // Setup rollback data to make sure that fails due to wrong volumeUuid being
   // passed, not because of some other reason.
-  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
-  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 41);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 41);
 
-  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
-  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
-  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
-  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
-  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
-  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
-  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
-          &fake_package_ce_path, &fake_package_de_path]() {
-      delete_dir_contents(rollback_ce_dir, true);
-      delete_dir_contents(rollback_de_dir, true);
-      delete_dir_contents(fake_package_ce_path, true);
-      delete_dir_contents(fake_package_de_path, true);
-      rmdir(rollback_ce_dir.c_str());
-      rmdir(rollback_de_dir.c_str());
-  };
-  auto scope_guard = android::base::make_scope_guard(deleter);
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
   EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_unique<std::string>("BAR"),
-          "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE));
+          "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE));
 }
 
 }  // namespace installd
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 1782aa2..e61eb6e 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -546,56 +546,86 @@
 }
 
 TEST_F(UtilsTest, TestRollbackPaths) {
-    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
-            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo"));
-    EXPECT_EQ("/data/misc_ce/10/rollback/com.foo",
-            create_data_misc_ce_rollback_package_path(nullptr, 10, "com.foo"));
+    EXPECT_EQ("/data/misc_ce/0/rollback/239/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 239, "com.foo"));
+    EXPECT_EQ("/data/misc_ce/10/rollback/37/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 10, 37, "com.foo"));
 
-    EXPECT_EQ("/data/misc_de/0/rollback/com.foo",
-            create_data_misc_de_rollback_package_path(nullptr, 0, "com.foo"));
-    EXPECT_EQ("/data/misc_de/10/rollback/com.foo",
-            create_data_misc_de_rollback_package_path(nullptr, 10, "com.foo"));
+    EXPECT_EQ("/data/misc_de/0/rollback/73/com.foo",
+            create_data_misc_de_rollback_package_path(nullptr, 0, 73, "com.foo"));
+    EXPECT_EQ("/data/misc_de/10/rollback/13/com.foo",
+            create_data_misc_de_rollback_package_path(nullptr, 10, 13, "com.foo"));
 
-    EXPECT_EQ("/data/misc_ce/0/rollback",
-            create_data_misc_ce_rollback_path(nullptr, 0));
-    EXPECT_EQ("/data/misc_ce/10/rollback",
-            create_data_misc_ce_rollback_path(nullptr, 10));
+    EXPECT_EQ("/data/misc_ce/0/rollback/57",
+            create_data_misc_ce_rollback_path(nullptr, 0, 57));
+    EXPECT_EQ("/data/misc_ce/10/rollback/1543",
+            create_data_misc_ce_rollback_path(nullptr, 10, 1543));
 
-    EXPECT_EQ("/data/misc_de/0/rollback",
-            create_data_misc_de_rollback_path(nullptr, 0));
-    EXPECT_EQ("/data/misc_de/10/rollback",
-            create_data_misc_de_rollback_path(nullptr, 10));
+    EXPECT_EQ("/data/misc_de/0/rollback/43",
+            create_data_misc_de_rollback_path(nullptr, 0, 43));
+    EXPECT_EQ("/data/misc_de/10/rollback/41",
+            create_data_misc_de_rollback_path(nullptr, 10, 41));
 
-    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
-            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 0));
-    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
-            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 239));
+    EXPECT_EQ("/data/misc_ce/0/rollback/17/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 17, "com.foo", 0));
+    EXPECT_EQ("/data/misc_ce/0/rollback/19/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 19, "com.foo", 239));
 
-    auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo");
-    auto deleter = [&rollback_ce_package_path]() {
-        delete_dir_contents_and_dir(rollback_ce_package_path, true /* ignore_if_missing */);
+    auto rollback_ce_path = create_data_misc_ce_rollback_path(nullptr, 0, 53);
+    auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, 53,
+            "com.foo");
+    auto deleter = [&rollback_ce_path]() {
+        delete_dir_contents_and_dir(rollback_ce_path, true /* ignore_if_missing */);
     };
     auto scope_guard = android::base::make_scope_guard(deleter);
 
-    ASSERT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));
+    EXPECT_NE(-1, mkdir(rollback_ce_path.c_str(), 700));
+    EXPECT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));
 
     ino_t ce_data_inode;
-    ASSERT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));
+    EXPECT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));
 
-    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
-            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", ce_data_inode));
+    EXPECT_EQ("/data/misc_ce/0/rollback/53/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 53, "com.foo", ce_data_inode));
     // Check that path defined by inode is picked even if it's not the same as
     // the fallback one.
-    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
-            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.bar", ce_data_inode));
+    EXPECT_EQ("/data/misc_ce/0/rollback/53/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 53, "com.bar", ce_data_inode));
 
     // These last couple of cases are never exercised in production because we
     // only snapshot apps in the primary data partition. Exercise them here for
     // the sake of completeness.
-    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_ce/0/rollback/com.example",
-            create_data_misc_ce_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
-    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_de/0/rollback/com.example",
-            create_data_misc_de_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
+    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_ce/0/rollback/7/com.example",
+            create_data_misc_ce_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, 7,
+                    "com.example"));
+    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_de/0/rollback/11/com.example",
+            create_data_misc_de_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, 11,
+                    "com.example"));
+}
+
+TEST_F(UtilsTest, TestCreateDirIfNeeded) {
+    system("mkdir -p /data/local/tmp/user/0");
+
+    auto deleter = [&]() {
+        delete_dir_contents_and_dir("/data/local/tmp/user/0", true /* ignore_if_missing */);
+    };
+    auto scope_guard = android::base::make_scope_guard(deleter);
+
+    // Create folder and check it's permissions.
+    ASSERT_EQ(0, create_dir_if_needed("/data/local/tmp/user/0/foo", 0700));
+    struct stat st;
+    ASSERT_EQ(0, stat("/data/local/tmp/user/0/foo", &st));
+    ASSERT_EQ(0700, st.st_mode & ALLPERMS);
+
+    // Check that create_dir_if_needed is no-op if folder already exists with
+    // correct permissions.
+    ASSERT_EQ(0, create_dir_if_needed("/data/local/tmp/user/0/foo", 0700));
+
+    // Check -1 is returned if folder exists but with different permissions.
+    ASSERT_EQ(-1, create_dir_if_needed("/data/local/tmp/user/0/foo", 0750));
+
+    // Check that call fails if parent doesn't exist.
+    ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
 }
 
 }  // namespace installd
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 5b487bb..52ca0df 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -197,32 +197,44 @@
     return StringPrintf("%s/user_de/%u", data.c_str(), userid);
 }
 
-
-std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user) {
+std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
     return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user);
 }
 
-std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user) {
+std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user) {
     return StringPrintf("%s/misc_de/%u/rollback", create_data_path(volume_uuid).c_str(), user);
 }
 
-std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
-        userid_t user, const char* package_name) {
-    return StringPrintf("%s/%s",
-           create_data_misc_ce_rollback_path(volume_uuid, user).c_str(), package_name);
+std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
+        int32_t snapshot_id) {
+    return StringPrintf("%s/%d", create_data_misc_ce_rollback_base_path(volume_uuid, user).c_str(),
+          snapshot_id);
+}
+
+std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user,
+        int32_t snapshot_id) {
+    return StringPrintf("%s/%d", create_data_misc_de_rollback_base_path(volume_uuid, user).c_str(),
+          snapshot_id);
 }
 
 std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
-        userid_t user, const char* package_name, ino_t ce_rollback_inode) {
-    auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name);
-    auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user);
+        userid_t user, int32_t snapshot_id, const char* package_name) {
+    return StringPrintf("%s/%s",
+           create_data_misc_ce_rollback_path(volume_uuid, user, snapshot_id).c_str(), package_name);
+}
+
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+        userid_t user, int32_t snapshot_id, const char* package_name, ino_t ce_rollback_inode) {
+    auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshot_id,
+            package_name);
+    auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user, snapshot_id);
     return resolve_ce_path_by_inode_or_fallback(user_path, ce_rollback_inode, fallback);
 }
 
 std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
-        userid_t user, const char* package_name) {
+        userid_t user, int32_t snapshot_id, const char* package_name) {
     return StringPrintf("%s/%s",
-           create_data_misc_de_rollback_path(volume_uuid, user).c_str(), package_name);
+           create_data_misc_de_rollback_path(volume_uuid, user, snapshot_id).c_str(), package_name);
 }
 
 /**
@@ -528,6 +540,30 @@
     return result;
 }
 
+int create_dir_if_needed(const std::string& pathname, mode_t perms) {
+    struct stat st;
+
+    int rc;
+    if ((rc = stat(pathname.c_str(), &st)) != 0) {
+        if (errno == ENOENT) {
+            return mkdir(pathname.c_str(), perms);
+        } else {
+            return rc;
+        }
+    } else if (!S_ISDIR(st.st_mode)) {
+        LOG(DEBUG) << pathname << " is not a folder";
+        return -1;
+    }
+
+    mode_t actual_perms = st.st_mode & ALLPERMS;
+    if (actual_perms != perms) {
+        LOG(WARNING) << pathname << " permissions " << actual_perms << " expected " << perms;
+        return -1;
+    }
+
+    return 0;
+}
+
 int delete_dir_contents(const std::string& pathname, bool ignore_if_missing) {
     return delete_dir_contents(pathname.c_str(), 0, nullptr, ignore_if_missing);
 }
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 0711b34..955d524 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -61,14 +61,18 @@
 std::string create_data_user_ce_package_path_as_user_link(
         const char* volume_uuid, userid_t userid, const char* package_name);
 
-std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user);
-std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
+        int32_t snapshot_id);
+std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user,
+        int32_t snapshot_id);
 std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
-        userid_t user, const char* package_name);
+        userid_t user, int32_t snapshot_id, const char* package_name);
 std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
-        userid_t user, const char* package_name, ino_t ce_rollback_inode);
+        userid_t user, int32_t snapshot_id, const char* package_name, ino_t ce_rollback_inode);
 std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
-        userid_t user, const char* package_name);
+        userid_t user, int32_t snapshot_id, const char* package_name);
 
 std::string create_data_media_path(const char* volume_uuid, userid_t userid);
 std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name);
@@ -109,6 +113,8 @@
 bool is_valid_filename(const std::string& name);
 bool is_valid_package_name(const std::string& packageName);
 
+int create_dir_if_needed(const std::string& pathname, mode_t mode);
+
 int delete_dir_contents(const std::string& pathname, bool ignore_if_missing = false);
 int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false);
 
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 0573187..0e79239 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -28,6 +28,7 @@
 
 #include <sys/cdefs.h>
 
+#include <android/data_space.h>
 #include <android/hardware_buffer.h>
 #include <android/hdr_metadata.h>
 #include <android/native_window.h>
@@ -316,6 +317,15 @@
                                         ASurfaceControl* surface_control, float alpha)
                                         __INTRODUCED_IN(29);
 
+/**
+ * Sets the data space of the surface_control's buffers.
+ *
+ * If no data space is set, the surface control defaults to ADATASPACE_SRGB.
+ */
+void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* transaction,
+                                            ASurfaceControl* surface_control, ADataSpace data_space)
+                                            __INTRODUCED_IN(29);
+
 /*
  * SMPTE ST 2086 "Mastering Display Color Volume" static metadata
  *
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index ff443c6..cd12fcd 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -24,6 +24,7 @@
 
 #include <utils/Vector.h>
 #include <input/InputWindow.h>
+#include <input/ISetInputWindowsListener.h>
 
 namespace android {
 
@@ -35,7 +36,8 @@
 public:
     DECLARE_META_INTERFACE(InputFlinger)
 
-    virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles) = 0;
+    virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles,
+            const sp<ISetInputWindowsListener>& setInputWindowsListener) = 0;
     virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
     virtual void registerInputChannel(const sp<InputChannel>& channel) = 0;
     virtual void unregisterInputChannel(const sp<InputChannel>& channel) = 0;
diff --git a/include/input/ISetInputWindowsListener.h b/include/input/ISetInputWindowsListener.h
new file mode 100644
index 0000000..15d31b2
--- /dev/null
+++ b/include/input/ISetInputWindowsListener.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class ISetInputWindowsListener : public IInterface {
+public:
+    DECLARE_META_INTERFACE(SetInputWindowsListener)
+    virtual void onSetInputWindowsFinished() = 0;
+};
+
+class BnSetInputWindowsListener: public BnInterface<ISetInputWindowsListener> {
+public:
+    enum SetInputWindowsTag : uint32_t {
+        ON_SET_INPUT_WINDOWS_FINISHED
+    };
+
+    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                uint32_t flags = 0) override;
+};
+
+}; // namespace android
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 34d164c..48ac88d 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -51,6 +51,15 @@
     // is intended to be a minimum way to distinguish from other active devices and may
     // reuse values that are not associated with an input anymore.
     uint16_t nonce;
+
+    /**
+     * Return InputDeviceIdentifier.name that has been adjusted as follows:
+     *     - all characters besides alphanumerics, dash,
+     *       and underscore have been replaced with underscores.
+     * This helps in situations where a file that matches the device name is needed,
+     * while conforming to the filename limitations.
+     */
+    std::string getCanonicalName() const;
 };
 
 /*
@@ -165,6 +174,13 @@
 extern std::string getInputDeviceConfigurationFilePathByName(
         const std::string& name, InputDeviceConfigurationFileType type);
 
+enum ReservedInputDeviceId : int32_t {
+    // Device id of a special "virtual" keyboard that is always present.
+    VIRTUAL_KEYBOARD_ID = -1,
+    // Device id of the "built-in" keyboard if there is one.
+    BUILT_IN_KEYBOARD_ID = 0,
+};
+
 } // namespace android
 
 #endif // _LIBINPUT_INPUT_DEVICE_H
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index 8b66f69..92da10c 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -25,15 +25,6 @@
 
 namespace android {
 
-enum {
-    /* Device id of the built in keyboard. */
-    DEVICE_ID_BUILT_IN_KEYBOARD = 0,
-
-    /* Device id of a generic virtual keyboard with a full layout that can be used
-     * to synthesize key events. */
-    DEVICE_ID_VIRTUAL_KEYBOARD = -1,
-};
-
 class KeyLayoutMap;
 class KeyCharacterMap;
 
diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h
index 640bf1f..b49c623 100644
--- a/include/input/TouchVideoFrame.h
+++ b/include/input/TouchVideoFrame.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 #include <sys/time.h>
+#include <ui/DisplayInfo.h>
 #include <vector>
 
 namespace android {
@@ -30,44 +31,48 @@
  */
 class TouchVideoFrame {
 public:
-    TouchVideoFrame(uint32_t width, uint32_t height, std::vector<int16_t> data,
-            const struct timeval& timestamp) :
-            mWidth(width), mHeight(height), mData(std::move(data)), mTimestamp(timestamp) {
-    }
+    TouchVideoFrame(uint32_t height, uint32_t width, std::vector<int16_t> data,
+            const struct timeval& timestamp);
 
-    bool operator==(const TouchVideoFrame& rhs) const {
-        return mWidth == rhs.mWidth
-                && mHeight == rhs.mHeight
-                && mData == rhs.mData
-                && mTimestamp.tv_sec == rhs.mTimestamp.tv_sec
-                && mTimestamp.tv_usec == rhs.mTimestamp.tv_usec;
-    }
+    bool operator==(const TouchVideoFrame& rhs) const;
 
     /**
-     * Width of the frame
-     */
-    uint32_t getWidth() const { return mWidth; }
-    /**
      * Height of the frame
      */
-    uint32_t getHeight() const { return mHeight; }
+    uint32_t getHeight() const;
+    /**
+     * Width of the frame
+     */
+    uint32_t getWidth() const;
     /**
      * The touch strength data.
      * The array is a 2-D row-major matrix, with dimensions (height, width).
      * Total size of the array should equal getHeight() * getWidth().
      * Data is allowed to be negative.
      */
-    const std::vector<int16_t>& getData() const { return mData; }
+    const std::vector<int16_t>& getData() const;
     /**
      * Time at which the heatmap was taken.
      */
-    const struct timeval& getTimestamp() const { return mTimestamp; }
+    const struct timeval& getTimestamp() const;
+
+    /**
+     * Rotate the video frame.
+     * The rotation value is an enum from ui/DisplayInfo.h
+     */
+    void rotate(int32_t orientation);
 
 private:
-    uint32_t mWidth;
     uint32_t mHeight;
+    uint32_t mWidth;
     std::vector<int16_t> mData;
     struct timeval mTimestamp;
+
+    /**
+     * Common method for 90 degree and 270 degree rotation
+     */
+    void rotateQuarterTurn(bool clockwise);
+    void rotate180();
 };
 
 } // namespace android
diff --git a/include/input/VirtualKeyMap.h b/include/input/VirtualKeyMap.h
index 24e0e0e..4f7cfb6 100644
--- a/include/input/VirtualKeyMap.h
+++ b/include/input/VirtualKeyMap.h
@@ -49,7 +49,7 @@
 public:
     ~VirtualKeyMap();
 
-    static status_t load(const std::string& filename, VirtualKeyMap** outMap);
+    static std::unique_ptr<VirtualKeyMap> load(const std::string& filename);
 
     inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
         return mVirtualKeys;
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 96ee295..cb0e08d 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -218,7 +218,7 @@
         if (!e) return; // out of memory
     }
 
-    e->mRequestingSid = true;
+    e->mRequestingSid = requestingSid;
 }
 
 BBinder::~BBinder()
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index f6381f7..0d30560 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -54,6 +54,7 @@
     virtual const String16&     getInterfaceDescriptor() const;
 
 protected:
+    typedef INTERFACE           BaseInterface;
     virtual IBinder*            onAsBinder();
 };
 
@@ -66,6 +67,7 @@
     explicit                    BpInterface(const sp<IBinder>& remote);
 
 protected:
+    typedef INTERFACE           BaseInterface;
     virtual IBinder*            onAsBinder();
 };
 
diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h
index 3bfd462..5fa2ff6 100644
--- a/libs/binder/include/binder/SafeInterface.h
+++ b/libs/binder/include/binder/SafeInterface.h
@@ -152,6 +152,12 @@
         return callParcel("writeParcelableVector",
                           [&]() { return parcel->writeParcelableVector(v); });
     }
+    status_t read(const Parcel& parcel, float* f) const {
+        return callParcel("readFloat", [&]() { return parcel.readFloat(f); });
+    }
+    status_t write(Parcel* parcel, float f) const {
+        return callParcel("writeFloat", [&]() { return parcel->writeFloat(f); });
+    }
 
     // Templates to handle integral types. We use a struct template to require that the called
     // function exactly matches the signedness and size of the argument (e.g., the argument isn't
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 68011bb..a96c9a0 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -16,7 +16,7 @@
 
 cc_library {
     name: "libbinder_ndk",
-    vendor_available: false,
+    vendor_available: true,
 
     export_include_dirs: [
         "include_ndk",
@@ -50,6 +50,13 @@
         "libandroid_runtime",
     ],
 
+    header_libs: [
+        "jni_headers",
+    ],
+    export_header_lib_headers: [
+        "jni_headers",
+    ],
+
     version_script: "libbinder_ndk.map.txt",
     stubs: {
         symbol_file: "libbinder_ndk.map.txt",
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_apex/android/binder_manager.h
index 80b6c07..055c79b 100644
--- a/libs/binder/ndk/include_apex/android/binder_manager.h
+++ b/libs/binder/ndk/include_apex/android/binder_manager.h
@@ -33,6 +33,15 @@
 binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance);
 
 /**
+ * Gets a binder object with this specific instance name. Will return nullptr immediately if the
+ * service is not available This also implicitly calls AIBinder_incStrong (so the caller of this
+ * function is responsible for calling AIBinder_decStrong).
+ *
+ * \param instance identifier of the service used to lookup the service.
+ */
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance);
+
+/**
  * Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
  * it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
  * for calling AIBinder_decStrong).
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index f0d25f7..655f4d5 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -91,6 +91,7 @@
     ABinderProcess_setThreadPoolMaxThreadCount; # apex
     ABinderProcess_startThreadPool; # apex
     AServiceManager_addService; # apex
+    AServiceManager_checkService; # apex
     AServiceManager_getService; # apex
   local:
     *;
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index 9ddc555..d0b166d 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -37,6 +37,18 @@
     status_t status = sm->addService(String16(instance), binder->getBinder());
     return PruneStatusT(status);
 }
+AIBinder* AServiceManager_checkService(const char* instance) {
+    if (instance == nullptr) {
+        return nullptr;
+    }
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->checkService(String16(instance));
+
+    sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder);
+    AIBinder_incStrong(ret.get());
+    return ret.get();
+}
 AIBinder* AServiceManager_getService(const char* instance) {
     if (instance == nullptr) {
         return nullptr;
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index c159d71..bff601e 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -35,6 +35,19 @@
 //     EXPECT_EQ(nullptr, foo.get());
 // }
 
+TEST(NdkBinder, CheckServiceThatDoesntExist) {
+    AIBinder* binder = AServiceManager_checkService("asdfghkl;");
+    ASSERT_EQ(nullptr, binder);
+}
+
+TEST(NdkBinder, CheckServiceThatDoesExist) {
+    AIBinder* binder = AServiceManager_checkService(kExistingNonNdkService);
+    EXPECT_NE(nullptr, binder);
+    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder));
+
+    AIBinder_decStrong(binder);
+}
+
 TEST(NdkBinder, DoubleNumber) {
     sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
     ASSERT_NE(foo, nullptr);
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index 6a16e24..3b1db27 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -229,6 +229,7 @@
         IncrementUint32,
         IncrementInt64,
         IncrementUint64,
+        IncrementFloat,
         IncrementTwo,
         Last,
     };
@@ -259,6 +260,7 @@
     virtual status_t increment(uint32_t a, uint32_t* aPlusOne) const = 0;
     virtual status_t increment(int64_t a, int64_t* aPlusOne) const = 0;
     virtual status_t increment(uint64_t a, uint64_t* aPlusOne) const = 0;
+    virtual status_t increment(float a, float* aPlusOne) const = 0;
 
     // This tests that input/output parameter interleaving works correctly
     virtual status_t increment(int32_t a, int32_t* aPlusOne, int32_t b,
@@ -353,6 +355,11 @@
         using Signature = status_t (ISafeInterfaceTest::*)(uint64_t, uint64_t*) const;
         return callRemote<Signature>(Tag::IncrementUint64, a, aPlusOne);
     }
+    status_t increment(float a, float* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature = status_t (ISafeInterfaceTest::*)(float, float*) const;
+        return callRemote<Signature>(Tag::IncrementFloat, a, aPlusOne);
+    }
     status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
         ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
         using Signature =
@@ -474,6 +481,11 @@
         *aPlusOne = a + 1;
         return NO_ERROR;
     }
+    status_t increment(float a, float* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *aPlusOne = a + 1.0f;
+        return NO_ERROR;
+    }
     status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
         ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
         *aPlusOne = a + 1;
@@ -555,6 +567,10 @@
                 using Signature = status_t (ISafeInterfaceTest::*)(uint64_t, uint64_t*) const;
                 return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
             }
+            case ISafeInterfaceTest::Tag::IncrementFloat: {
+                using Signature = status_t (ISafeInterfaceTest::*)(float, float*) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
             case ISafeInterfaceTest::Tag::IncrementTwo: {
                 using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t,
                                                                    int32_t*) const;
@@ -804,6 +820,14 @@
     ASSERT_EQ(a + 1, aPlusOne);
 }
 
+TEST_F(SafeInterfaceTest, TestIncrementFloat) {
+    const float a = 1.0f;
+    float aPlusOne = 0.0f;
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a + 1.0f, aPlusOne);
+}
+
 TEST_F(SafeInterfaceTest, TestIncrementTwo) {
     const int32_t a = 1;
     int32_t aPlusOne = 0;
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 280c14a..d940752 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -17,14 +17,17 @@
 
     srcs: [
         "GraphicsEnv.cpp",
+        "IGpuService.cpp"
     ],
 
     cflags: ["-Wall", "-Werror"],
 
     shared_libs: [
         "libbase",
+        "libbinder",
         "libcutils",
         "liblog",
+        "libutils",
     ],
 
     export_include_dirs: ["include"],
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index b8c6cfe..13c0d87 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 //#define LOG_NDEBUG 1
 #define LOG_TAG "GraphicsEnv"
+
 #include <graphicsenv/GraphicsEnv.h>
 
 #include <dlfcn.h>
@@ -25,15 +28,16 @@
 #include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <android/dlext.h>
+#include <binder/IServiceManager.h>
 #include <cutils/properties.h>
+#include <graphicsenv/IGpuService.h>
 #include <log/log.h>
 #include <sys/prctl.h>
+#include <utils/Trace.h>
 
 #include <memory>
 #include <string>
 
-#include <dlfcn.h>
-
 // TODO(b/37049319) Get this from a header once one exists
 extern "C" {
 android_namespace_t* android_get_exported_namespace(const char*);
@@ -142,14 +146,144 @@
     return 0;
 }
 
-void GraphicsEnv::setDriverPath(const std::string path) {
-    if (!mDriverPath.empty()) {
-        ALOGV("ignoring attempt to change driver path from '%s' to '%s'", mDriverPath.c_str(),
-              path.c_str());
+void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path,
+                                                 const std::string sphalLibraries) {
+    if (!mDriverPath.empty() || !mSphalLibraries.empty()) {
+        ALOGV("ignoring attempt to change driver path from '%s' to '%s' or change sphal libraries "
+              "from '%s' to '%s'",
+              mDriverPath.c_str(), path.c_str(), mSphalLibraries.c_str(), sphalLibraries.c_str());
         return;
     }
-    ALOGV("setting driver path to '%s'", path.c_str());
+    ALOGV("setting driver path to '%s' and sphal libraries to '%s'", path.c_str(),
+          sphalLibraries.c_str());
     mDriverPath = path;
+    mSphalLibraries = sphalLibraries;
+}
+
+void GraphicsEnv::setGpuStats(const std::string& driverPackageName,
+                              const std::string& driverVersionName, uint64_t driverVersionCode,
+                              int64_t driverBuildTime, const std::string& appPackageName) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mStatsLock);
+    ALOGV("setGpuStats:\n"
+          "\tdriverPackageName[%s]\n"
+          "\tdriverVersionName[%s]\n"
+          "\tdriverVersionCode[%" PRIu64 "]\n"
+          "\tdriverBuildTime[%" PRId64 "]\n"
+          "\tappPackageName[%s]\n",
+          driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
+          appPackageName.c_str());
+
+    mGpuStats.driverPackageName = driverPackageName;
+    mGpuStats.driverVersionName = driverVersionName;
+    mGpuStats.driverVersionCode = driverVersionCode;
+    mGpuStats.driverBuildTime = driverBuildTime;
+    mGpuStats.appPackageName = appPackageName;
+}
+
+void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mStatsLock);
+    switch (driver) {
+        case GraphicsEnv::Driver::GL:
+        case GraphicsEnv::Driver::GL_UPDATED:
+        case GraphicsEnv::Driver::ANGLE: {
+            if (mGpuStats.glDriverToLoad == GraphicsEnv::Driver::NONE) {
+                mGpuStats.glDriverToLoad = driver;
+                break;
+            }
+
+            if (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE) {
+                mGpuStats.glDriverFallback = driver;
+            }
+            break;
+        }
+        case Driver::VULKAN:
+        case Driver::VULKAN_UPDATED: {
+            if (mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::NONE) {
+                mGpuStats.vkDriverToLoad = driver;
+                break;
+            }
+
+            if (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE) {
+                mGpuStats.vkDriverFallback = driver;
+            }
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+void GraphicsEnv::setDriverLoaded(GraphicsEnv::Api api, bool isLoaded, int64_t driverLoadingTime) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mStatsLock);
+    GraphicsEnv::Driver driver = GraphicsEnv::Driver::NONE;
+    bool isIntendedDriverLoaded = false;
+    if (api == GraphicsEnv::Api::API_GL) {
+        driver = mGpuStats.glDriverToLoad;
+        isIntendedDriverLoaded = isLoaded &&
+                ((mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE) ||
+                 (mGpuStats.glDriverToLoad == mGpuStats.glDriverFallback));
+    } else {
+        driver = mGpuStats.vkDriverToLoad;
+        isIntendedDriverLoaded =
+                isLoaded && (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE);
+    }
+
+    sendGpuStatsLocked(driver, isIntendedDriverLoaded, driverLoadingTime);
+}
+
+void GraphicsEnv::clearDriverLoadingInfo(GraphicsEnv::Api api) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mStatsLock);
+    if (api == GraphicsEnv::Api::API_GL) {
+        mGpuStats.glDriverToLoad = GraphicsEnv::Driver::NONE;
+        mGpuStats.glDriverFallback = GraphicsEnv::Driver::NONE;
+    }
+}
+
+static sp<IGpuService> getGpuService() {
+    const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
+    if (!binder) {
+        ALOGE("Failed to get gpu service");
+        return nullptr;
+    }
+
+    return interface_cast<IGpuService>(binder);
+}
+
+void GraphicsEnv::sendGpuStatsLocked(GraphicsEnv::Driver driver, bool isDriverLoaded,
+                                     int64_t driverLoadingTime) {
+    ATRACE_CALL();
+
+    // Do not sendGpuStats for those skipping the GraphicsEnvironment setup
+    if (mGpuStats.appPackageName.empty()) return;
+
+    ALOGV("sendGpuStats:\n"
+          "\tdriverPackageName[%s]\n"
+          "\tdriverVersionName[%s]\n"
+          "\tdriverVersionCode[%" PRIu64 "]\n"
+          "\tdriverBuildTime[%" PRId64 "]\n"
+          "\tappPackageName[%s]\n"
+          "\tdriver[%d]\n"
+          "\tisDriverLoaded[%d]\n"
+          "\tdriverLoadingTime[%" PRId64 "]",
+          mGpuStats.driverPackageName.c_str(), mGpuStats.driverVersionName.c_str(),
+          mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(),
+          static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
+
+    const sp<IGpuService> gpuService = getGpuService();
+    if (gpuService) {
+        gpuService->setGpuStats(mGpuStats.driverPackageName, mGpuStats.driverVersionName,
+                                mGpuStats.driverVersionCode, mGpuStats.driverBuildTime,
+                                mGpuStats.appPackageName, driver, isDriverLoaded,
+                                driverLoadingTime);
+    }
 }
 
 void* GraphicsEnv::loadLibrary(std::string name) {
@@ -265,28 +399,28 @@
         return false;
     }
 
-    return mUseAngle;
+    return (mUseAngle == YES) ? true : false;
 }
 
 void GraphicsEnv::updateUseAngle() {
-    mUseAngle = false;
+    mUseAngle = NO;
 
     const char* ANGLE_PREFER_ANGLE = "angle";
     const char* ANGLE_PREFER_NATIVE = "native";
 
     if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) {
         ALOGV("User set \"Developer Options\" to force the use of ANGLE");
-        mUseAngle = true;
+        mUseAngle = YES;
     } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) {
         ALOGV("User set \"Developer Options\" to force the use of Native");
-        mUseAngle = false;
+        mUseAngle = NO;
     } else {
         // The "Developer Options" value wasn't set to force the use of ANGLE.  Need to temporarily
         // load ANGLE and call the updatable opt-in/out logic:
         void* featureSo = loadLibrary("feature_support");
         if (featureSo) {
             ALOGV("loaded ANGLE's opt-in/out logic from namespace");
-            mUseAngle = checkAngleRules(featureSo);
+            mUseAngle = checkAngleRules(featureSo) ? YES : NO;
             dlclose(featureSo);
             featureSo = nullptr;
         } else {
@@ -298,6 +432,13 @@
 void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
                                const std::string developerOptIn, const int rulesFd,
                                const long rulesOffset, const long rulesLength) {
+    if (mUseAngle != UNKNOWN) {
+        // We've already figured out an answer for this app, so just return.
+        ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(),
+              (mUseAngle == YES) ? "true" : "false");
+        return;
+    }
+
     ALOGV("setting ANGLE path to '%s'", path.c_str());
     mAnglePath = path;
     ALOGV("setting ANGLE app name to '%s'", appName.c_str());
@@ -399,6 +540,23 @@
             mDriverNamespace = nullptr;
             return;
         }
+
+        if (mSphalLibraries.empty()) return;
+
+        // Make additional libraries in sphal to be accessible
+        auto sphalNamespace = android_get_exported_namespace("sphal");
+        if (!sphalNamespace) {
+            ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
+                  mSphalLibraries.c_str());
+            mDriverNamespace = nullptr;
+            return;
+        }
+
+        if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
+            ALOGE("Failed to link sphal namespace[%s]", dlerror());
+            mDriverNamespace = nullptr;
+            return;
+        }
     });
 
     return mDriverNamespace;
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
new file mode 100644
index 0000000..f755e00
--- /dev/null
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "GpuService"
+
+#include <graphicsenv/IGpuService.h>
+
+#include <binder/IResultReceiver.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class BpGpuService : public BpInterface<IGpuService> {
+public:
+    explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
+
+    virtual void setGpuStats(const std::string& driverPackageName,
+                             const std::string& driverVersionName, uint64_t driverVersionCode,
+                             int64_t driverBuildTime, const std::string& appPackageName,
+                             GraphicsEnv::Driver driver, bool isDriverLoaded,
+                             int64_t driverLoadingTime) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
+
+        data.writeUtf8AsUtf16(driverPackageName);
+        data.writeUtf8AsUtf16(driverVersionName);
+        data.writeUint64(driverVersionCode);
+        data.writeInt64(driverBuildTime);
+        data.writeUtf8AsUtf16(appPackageName);
+        data.writeInt32(static_cast<int32_t>(driver));
+        data.writeBool(isDriverLoaded);
+        data.writeInt64(driverLoadingTime);
+
+        remote()->transact(BnGpuService::SET_GPU_STATS, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(GpuService, "android.graphicsenv.IGpuService");
+
+status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                  uint32_t flags) {
+    ALOGV("onTransact code[0x%X]", code);
+
+    status_t status;
+    switch (code) {
+        case SET_GPU_STATS: {
+            CHECK_INTERFACE(IGpuService, data, reply);
+
+            std::string driverPackageName;
+            if ((status = data.readUtf8FromUtf16(&driverPackageName)) != OK) return status;
+
+            std::string driverVersionName;
+            if ((status = data.readUtf8FromUtf16(&driverVersionName)) != OK) return status;
+
+            uint64_t driverVersionCode;
+            if ((status = data.readUint64(&driverVersionCode)) != OK) return status;
+
+            int64_t driverBuildTime;
+            if ((status = data.readInt64(&driverBuildTime)) != OK) return status;
+
+            std::string appPackageName;
+            if ((status = data.readUtf8FromUtf16(&appPackageName)) != OK) return status;
+
+            int32_t driver;
+            if ((status = data.readInt32(&driver)) != OK) return status;
+
+            bool isDriverLoaded;
+            if ((status = data.readBool(&isDriverLoaded)) != OK) return status;
+
+            int64_t driverLoadingTime;
+            if ((status = data.readInt64(&driverLoadingTime)) != OK) return status;
+
+            setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
+                        appPackageName, static_cast<GraphicsEnv::Driver>(driver), isDriverLoaded,
+                        driverLoadingTime);
+
+            return OK;
+        }
+        case SHELL_COMMAND_TRANSACTION: {
+            int in = data.readFileDescriptor();
+            int out = data.readFileDescriptor();
+            int err = data.readFileDescriptor();
+
+            std::vector<String16> args;
+            data.readString16Vector(&args);
+
+            sp<IBinder> unusedCallback;
+            if ((status = data.readNullableStrongBinder(&unusedCallback)) != OK) return status;
+
+            sp<IResultReceiver> resultReceiver;
+            if ((status = data.readNullableStrongBinder(&resultReceiver)) != OK) return status;
+
+            status = shellCommand(in, out, err, args);
+            if (resultReceiver != nullptr) resultReceiver->send(status);
+
+            return OK;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+} // namespace android
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index ed08882..cb4239f 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -29,6 +29,45 @@
 
 class GraphicsEnv {
 public:
+    enum Api {
+        API_GL = 0,
+        API_VK = 1,
+    };
+
+    enum Driver {
+        NONE = 0,
+        GL = 1,
+        GL_UPDATED = 2,
+        VULKAN = 3,
+        VULKAN_UPDATED = 4,
+        ANGLE = 5,
+    };
+
+private:
+    struct GpuStats {
+        std::string driverPackageName;
+        std::string driverVersionName;
+        uint64_t driverVersionCode;
+        int64_t driverBuildTime;
+        std::string appPackageName;
+        Driver glDriverToLoad;
+        Driver glDriverFallback;
+        Driver vkDriverToLoad;
+        Driver vkDriverFallback;
+
+        GpuStats()
+              : driverPackageName(""),
+                driverVersionName(""),
+                driverVersionCode(0),
+                driverBuildTime(0),
+                appPackageName(""),
+                glDriverToLoad(Driver::NONE),
+                glDriverFallback(Driver::NONE),
+                vkDriverToLoad(Driver::NONE),
+                vkDriverFallback(Driver::NONE) {}
+    };
+
+public:
     static GraphicsEnv& getInstance();
 
     int getCanLoadSystemLibraries();
@@ -38,8 +77,18 @@
     // (drivers must be stored uncompressed and page aligned); such elements
     // in the search path must have a '!' after the zip filename, e.g.
     //     /data/app/com.example.driver/base.apk!/lib/arm64-v8a
-    void setDriverPath(const std::string path);
+    // Also set additional required sphal libraries to the linker for loading
+    // graphics drivers. The string is a list of libraries separated by ':',
+    // which is required by android_link_namespaces.
+    void setDriverPathAndSphalLibraries(const std::string path, const std::string sphalLibraries);
     android_namespace_t* getDriverNamespace();
+    void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
+                     uint64_t versionCode, int64_t driverBuildTime,
+                     const std::string& appPackageName);
+    void setDriverToLoad(Driver driver);
+    void setDriverLoaded(Api api, bool isDriverLoaded, int64_t driverLoadingTime);
+    void clearDriverLoadingInfo(Api api);
+    void sendGpuStatsLocked(Driver driver, bool isDriverLoaded, int64_t driverLoadingTime);
 
     bool shouldUseAngle(std::string appName);
     bool shouldUseAngle();
@@ -64,17 +113,22 @@
     const std::string& getDebugLayersGLES();
 
 private:
+    enum UseAngle { UNKNOWN, YES, NO };
+
     void* loadLibrary(std::string name);
     bool checkAngleRules(void* so);
     void updateUseAngle();
 
     GraphicsEnv() = default;
     std::string mDriverPath;
+    std::string mSphalLibraries;
+    std::mutex mStatsLock;
+    GpuStats mGpuStats;
     std::string mAnglePath;
     std::string mAngleAppName;
     std::string mAngleDeveloperOptIn;
     std::vector<char> mRulesBuffer;
-    bool mUseAngle;
+    UseAngle mUseAngle = UNKNOWN;
     std::string mDebugLayers;
     std::string mDebugLayersGLES;
     std::string mLayerPaths;
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
new file mode 100644
index 0000000..5f9340d
--- /dev/null
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -0,0 +1,57 @@
+/*
+ * 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 <binder/IInterface.h>
+#include <cutils/compiler.h>
+#include <graphicsenv/GraphicsEnv.h>
+
+#include <vector>
+
+namespace android {
+
+/*
+ * This class defines the Binder IPC interface for GPU-related queries and
+ * control.
+ */
+class IGpuService : public IInterface {
+public:
+    DECLARE_META_INTERFACE(GpuService)
+
+    // set GPU stats from GraphicsEnvironment.
+    virtual void setGpuStats(const std::string& driverPackageName,
+                             const std::string& driverVersionName, uint64_t driverVersionCode,
+                             int64_t driverBuildTime, const std::string& appPackageName,
+                             GraphicsEnv::Driver driver, bool isDriverLoaded,
+                             int64_t driverLoadingTime) = 0;
+};
+
+class BnGpuService : public BnInterface<IGpuService> {
+public:
+    enum IGpuServiceTag {
+        SET_GPU_STATS = IBinder::FIRST_CALL_TRANSACTION,
+        // Always append new enum to the end.
+    };
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
+
+protected:
+    virtual status_t shellCommand(int in, int out, int err, std::vector<String16>& args) = 0;
+};
+
+} // namespace android
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index f40eb6c..0510492 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -104,6 +104,7 @@
         "IGraphicBufferConsumer.cpp",
         "IGraphicBufferProducer.cpp",
         "IProducerListener.cpp",
+        "IRegionSamplingListener.cpp",
         "ISurfaceComposer.cpp",
         "ISurfaceComposerClient.cpp",
         "ITransactionCompletedListener.cpp",
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index d997674..8907de4 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -651,7 +651,7 @@
     }
 };
 
-IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer,
+IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer,
         "android.gui.IGraphicBufferProducer");
 
 // ----------------------------------------------------------------------
diff --git a/libs/gui/IRegionSamplingListener.cpp b/libs/gui/IRegionSamplingListener.cpp
new file mode 100644
index 0000000..40cbfce
--- /dev/null
+++ b/libs/gui/IRegionSamplingListener.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "IRegionSamplingListener"
+//#define LOG_NDEBUG 0
+
+#include <gui/IRegionSamplingListener.h>
+
+namespace android {
+
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+    ON_SAMPLE_COLLECTED = IBinder::FIRST_CALL_TRANSACTION,
+    LAST = ON_SAMPLE_COLLECTED,
+};
+
+} // Anonymous namespace
+
+class BpRegionSamplingListener : public SafeBpInterface<IRegionSamplingListener> {
+public:
+    explicit BpRegionSamplingListener(const sp<IBinder>& impl)
+          : SafeBpInterface<IRegionSamplingListener>(impl, "BpRegionSamplingListener") {}
+
+    ~BpRegionSamplingListener() override;
+
+    void onSampleCollected(float medianLuma) override {
+        callRemoteAsync<decltype(
+                &IRegionSamplingListener::onSampleCollected)>(Tag::ON_SAMPLE_COLLECTED, medianLuma);
+    }
+};
+
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpRegionSamplingListener::~BpRegionSamplingListener() = default;
+
+IMPLEMENT_META_INTERFACE(RegionSamplingListener, "android.gui.IRegionSamplingListener");
+
+status_t BnRegionSamplingListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                              uint32_t flags) {
+    if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+    auto tag = static_cast<Tag>(code);
+    switch (tag) {
+        case Tag::ON_SAMPLE_COLLECTED:
+            return callLocalAsync(data, reply, &IRegionSamplingListener::onSampleCollected);
+    }
+}
+
+} // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index fd30e3b..f77eeb2 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -26,6 +26,7 @@
 
 #include <gui/IDisplayEventConnection.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <gui/IRegionSamplingListener.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerDebugInfo.h>
@@ -275,12 +276,25 @@
         remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply);
     }
 
-    virtual sp<IBinder> getBuiltInDisplay(int32_t id)
-    {
+    virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeInt32(id);
-        remote()->transact(BnSurfaceComposer::GET_BUILT_IN_DISPLAY, data, &reply);
+        if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) ==
+            NO_ERROR) {
+            std::vector<PhysicalDisplayId> displayIds;
+            if (reply.readUint64Vector(&displayIds) == NO_ERROR) {
+                return displayIds;
+            }
+        }
+
+        return {};
+    }
+
+    virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeUint64(displayId);
+        remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN, data, &reply);
         return reply.readStrongBinder();
     }
 
@@ -741,6 +755,57 @@
         error = reply.readBool(outIsWideColorDisplay);
         return error;
     }
+
+    virtual status_t addRegionSamplingListener(const Rect& samplingArea,
+                                               const sp<IBinder>& stopLayerHandle,
+                                               const sp<IRegionSamplingListener>& listener) {
+        Parcel data, reply;
+        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write interface token");
+            return error;
+        }
+        error = data.write(samplingArea);
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write sampling area");
+            return error;
+        }
+        error = data.writeStrongBinder(stopLayerHandle);
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write stop layer handle");
+            return error;
+        }
+        error = data.writeStrongBinder(IInterface::asBinder(listener));
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write listener");
+            return error;
+        }
+        error = remote()->transact(BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER, data, &reply);
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to transact");
+        }
+        return error;
+    }
+
+    virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) {
+        Parcel data, reply;
+        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write interface token");
+            return error;
+        }
+        error = data.writeStrongBinder(IInterface::asBinder(listener));
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write listener");
+            return error;
+        }
+        error = remote()->transact(BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER, data,
+                                   &reply);
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to transact");
+        }
+        return error;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -896,10 +961,10 @@
             destroyDisplay(display);
             return NO_ERROR;
         }
-        case GET_BUILT_IN_DISPLAY: {
+        case GET_PHYSICAL_DISPLAY_TOKEN: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            int32_t id = data.readInt32();
-            sp<IBinder> display(getBuiltInDisplay(id));
+            PhysicalDisplayId displayId = data.readUint64();
+            sp<IBinder> display = getPhysicalDisplayToken(displayId);
             reply->writeStrongBinder(display);
             return NO_ERROR;
         }
@@ -1216,12 +1281,46 @@
             }
             return error;
         }
+        case GET_PHYSICAL_DISPLAY_IDS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            return reply->writeUint64Vector(getPhysicalDisplayIds());
+        }
+        case ADD_REGION_SAMPLING_LISTENER: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            Rect samplingArea;
+            status_t result = data.read(samplingArea);
+            if (result != NO_ERROR) {
+                ALOGE("addRegionSamplingListener: Failed to read sampling area");
+                return result;
+            }
+            sp<IBinder> stopLayerHandle;
+            result = data.readNullableStrongBinder(&stopLayerHandle);
+            if (result != NO_ERROR) {
+                ALOGE("addRegionSamplingListener: Failed to read stop layer handle");
+                return result;
+            }
+            sp<IRegionSamplingListener> listener;
+            result = data.readNullableStrongBinder(&listener);
+            if (result != NO_ERROR) {
+                ALOGE("addRegionSamplingListener: Failed to read listener");
+                return result;
+            }
+            return addRegionSamplingListener(samplingArea, stopLayerHandle, listener);
+        }
+        case REMOVE_REGION_SAMPLING_LISTENER: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IRegionSamplingListener> listener;
+            status_t result = data.readNullableStrongBinder(&listener);
+            if (result != NO_ERROR) {
+                ALOGE("removeRegionSamplingListener: Failed to read listener");
+                return result;
+            }
+            return removeRegionSamplingListener(listener);
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
     }
 }
 
-// ----------------------------------------------------------------------------
-
-};
+} // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 206bc30..962d263 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -414,10 +414,13 @@
             .insert(transferTouchFocusCommands.end(),
                     std::make_move_iterator(other.transferTouchFocusCommands.begin()),
                     std::make_move_iterator(other.transferTouchFocusCommands.end()));
+
+    syncInputWindows |= other.syncInputWindows;
 }
 
 void InputWindowCommands::clear() {
     transferTouchFocusCommands.clear();
+    syncInputWindows = false;
 }
 
 void InputWindowCommands::write(Parcel& output) const {
@@ -426,6 +429,8 @@
         output.writeStrongBinder(transferTouchFocusCommand.fromToken);
         output.writeStrongBinder(transferTouchFocusCommand.toToken);
     }
+
+    output.writeBool(syncInputWindows);
 }
 
 void InputWindowCommands::read(const Parcel& input) {
@@ -437,6 +442,8 @@
         transferTouchFocusCommand.toToken = input.readStrongBinder();
         transferTouchFocusCommands.emplace_back(transferTouchFocusCommand);
     }
+
+    syncInputWindows = input.readBool();
 }
 
 }; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 1f726b2..3affa23 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -321,8 +321,11 @@
 status_t Surface::getWideColorSupport(bool* supported) {
     ATRACE_CALL();
 
-    sp<IBinder> display(
-        composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    const sp<IBinder> display = composerService()->getInternalDisplayToken();
+    if (display == nullptr) {
+        return NAME_NOT_FOUND;
+    }
+
     *supported = false;
     status_t error = composerService()->isWideColorDisplay(display, supported);
     return error;
@@ -331,8 +334,11 @@
 status_t Surface::getHdrSupport(bool* supported) {
     ATRACE_CALL();
 
-    sp<IBinder> display(
-        composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    const sp<IBinder> display = composerService()->getInternalDisplayToken();
+    if (display == nullptr) {
+        return NAME_NOT_FOUND;
+    }
+
     HdrCapabilities hdrCapabilities;
     status_t err =
         composerService()->getHdrCapabilities(display, &hdrCapabilities);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 92b5588..8c2538c 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -383,6 +383,7 @@
     other.mListenerCallbacks.clear();
 
     mInputWindowCommands.merge(other.mInputWindowCommands);
+    other.mInputWindowCommands.clear();
 
     return *this;
 }
@@ -484,8 +485,20 @@
     return ComposerService::getComposerService()->destroyDisplay(display);
 }
 
-sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
-    return ComposerService::getComposerService()->getBuiltInDisplay(id);
+std::vector<PhysicalDisplayId> SurfaceComposerClient::getPhysicalDisplayIds() {
+    return ComposerService::getComposerService()->getPhysicalDisplayIds();
+}
+
+std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
+    return ComposerService::getComposerService()->getInternalDisplayId();
+}
+
+sp<IBinder> SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId displayId) {
+    return ComposerService::getComposerService()->getPhysicalDisplayToken(displayId);
+}
+
+sp<IBinder> SurfaceComposerClient::getInternalDisplayToken() {
+    return ComposerService::getComposerService()->getInternalDisplayToken();
 }
 
 void SurfaceComposerClient::Transaction::setAnimationTransaction() {
@@ -1070,6 +1083,11 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() {
+    mInputWindowCommands.syncInputWindows = true;
+    return *this;
+}
+
 #endif
 
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorTransform(
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 008f520..55488da 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -63,23 +63,25 @@
 
 SurfaceControl::~SurfaceControl()
 {
+    // Avoid reparenting the server-side surface to null if we are not the owner of it,
+    // meaning that we retrieved it from another process.
     if (mClient != nullptr && mHandle != nullptr && mOwned) {
         SurfaceComposerClient::doDropReferenceTransaction(mHandle, mClient->getClient());
     }
-    mClient.clear();
-    mHandle.clear();
-    mGraphicBufferProducer.clear();
-    IPCThreadState::self()->flushCommands();
+    release();
 }
 
 void SurfaceControl::destroy()
 {
-    // Avoid destroying the server-side surface if we are not the owner of it, meaning that we
-    // retrieved it from another process.
-    if (isValid() && mOwned) {
+    if (isValid()) {
         SurfaceComposerClient::Transaction().reparent(this, nullptr).apply();
     }
-    // clear all references and trigger an IPC now, to make sure things
+    release();
+}
+
+void SurfaceControl::release()
+{
+    // Trigger an IPC now, to make sure things
     // happen without delay, since these resources are quite heavy.
     mClient.clear();
     mHandle.clear();
@@ -87,17 +89,6 @@
     IPCThreadState::self()->flushCommands();
 }
 
-void SurfaceControl::clear()
-{
-    // here, the window manager tells us explicitly that we should destroy
-    // the surface's resource. Soon after this call, it will also release
-    // its last reference (which will call the dtor); however, it is possible
-    // that a client living in the same process still holds references which
-    // would delay the call to the dtor -- that is why we need this explicit
-    // "clear()" call.
-    destroy();
-}
-
 void SurfaceControl::disconnect() {
     if (mGraphicBufferProducer != nullptr) {
         mGraphicBufferProducer->disconnect(
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index a4102df..8c3f463 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -58,7 +58,7 @@
 
         struct Header {
             uint32_t type;
-            uint32_t id;
+            PhysicalDisplayId displayId;
             nsecs_t timestamp __attribute__((aligned(8)));
         };
 
diff --git a/libs/gui/include/gui/IRegionSamplingListener.h b/libs/gui/include/gui/IRegionSamplingListener.h
new file mode 100644
index 0000000..1803d9a
--- /dev/null
+++ b/libs/gui/include/gui/IRegionSamplingListener.h
@@ -0,0 +1,43 @@
+/*
+ * 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 <cstdint>
+#include <vector>
+
+#include <binder/IInterface.h>
+#include <binder/SafeInterface.h>
+
+namespace android {
+
+class IRegionSamplingListener : public IInterface {
+public:
+    DECLARE_META_INTERFACE(RegionSamplingListener)
+
+    virtual void onSampleCollected(float medianLuma) = 0;
+};
+
+class BnRegionSamplingListener : public SafeBnInterface<IRegionSamplingListener> {
+public:
+    BnRegionSamplingListener()
+          : SafeBnInterface<IRegionSamplingListener>("BnRegionSamplingListener") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 7146b7d..e6700e7 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -34,6 +34,7 @@
 #include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 
+#include <optional>
 #include <vector>
 
 namespace android {
@@ -49,6 +50,7 @@
 class IDisplayEventConnection;
 class IGraphicBufferProducer;
 class ISurfaceComposerClient;
+class IRegionSamplingListener;
 class Rect;
 enum class FrameEvent;
 
@@ -71,11 +73,6 @@
         eEarlyWakeup = 0x04
     };
 
-    enum {
-        eDisplayIdMain = 0,
-        eDisplayIdHdmi = 1
-    };
-
     enum Rotation {
         eRotateNone = 0,
         eRotate90   = 1,
@@ -88,7 +85,7 @@
         eVsyncSourceSurfaceFlinger = 1
     };
 
-    /* 
+    /*
      * Create a connection with SurfaceFlinger.
      */
     virtual sp<ISurfaceComposerClient> createConnection() = 0;
@@ -108,10 +105,26 @@
      */
     virtual void destroyDisplay(const sp<IBinder>& display) = 0;
 
-    /* get the token for the existing default displays. possible values
-     * for id are eDisplayIdMain and eDisplayIdHdmi.
+    /* get stable IDs for connected physical displays.
      */
-    virtual sp<IBinder> getBuiltInDisplay(int32_t id) = 0;
+    virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
+
+    // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+    std::optional<PhysicalDisplayId> getInternalDisplayId() const {
+        const auto displayIds = getPhysicalDisplayIds();
+        return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
+    }
+
+    /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
+     * DisplayEventReceiver hotplug event.
+     */
+    virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const = 0;
+
+    // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+    sp<IBinder> getInternalDisplayToken() const {
+        const auto displayId = getInternalDisplayId();
+        return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+    }
 
     /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
     virtual void setTransactionState(const Vector<ComposerState>& state,
@@ -326,6 +339,26 @@
      */
     virtual status_t isWideColorDisplay(const sp<IBinder>& token,
                                         bool* outIsWideColorDisplay) const = 0;
+
+    /* Registers a listener to stream median luma updates from SurfaceFlinger.
+     *
+     * The sampling area is bounded by both samplingArea and the given stopLayerHandle
+     * (i.e., only layers behind the stop layer will be captured and sampled).
+     *
+     * Multiple listeners may be provided so long as they have independent listeners.
+     * If multiple listeners are provided, the effective sampling region for each listener will
+     * be bounded by whichever stop layer has a lower Z value.
+     *
+     * Requires the same permissions as captureLayers and captureScreen.
+     */
+    virtual status_t addRegionSamplingListener(const Rect& samplingArea,
+                                               const sp<IBinder>& stopLayerHandle,
+                                               const sp<IRegionSamplingListener>& listener) = 0;
+
+    /*
+     * Removes a listener that was streaming median luma updates from SurfaceFlinger.
+     */
+    virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -341,7 +374,7 @@
         CREATE_DISPLAY_EVENT_CONNECTION,
         CREATE_DISPLAY,
         DESTROY_DISPLAY,
-        GET_BUILT_IN_DISPLAY,
+        GET_PHYSICAL_DISPLAY_TOKEN,
         SET_TRANSACTION_STATE,
         AUTHENTICATE_SURFACE,
         GET_SUPPORTED_FRAME_TIMESTAMPS,
@@ -370,6 +403,10 @@
         GET_PROTECTED_CONTENT_SUPPORT,
         IS_WIDE_COLOR_DISPLAY,
         GET_DISPLAY_NATIVE_PRIMARIES,
+        GET_PHYSICAL_DISPLAY_IDS,
+        ADD_REGION_SAMPLING_LISTENER,
+        REMOVE_REGION_SAMPLING_LISTENER,
+
         // Always append new enum to the end.
     };
 
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index c780c07..32d7391 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -254,6 +254,7 @@
     };
 
     std::vector<TransferTouchFocusCommand> transferTouchFocusCommands;
+    bool syncInputWindows{false};
 
     void merge(const InputWindowCommands& other);
     void clear();
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 044106d..cb38209 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -196,9 +196,13 @@
     //! Destroy a virtual display
     static void destroyDisplay(const sp<IBinder>& display);
 
-    //! Get the token for the existing default displays.
-    //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi.
-    static sp<IBinder> getBuiltInDisplay(int32_t id);
+    //! Get stable IDs for connected physical displays
+    static std::vector<PhysicalDisplayId> getPhysicalDisplayIds();
+    static std::optional<PhysicalDisplayId> getInternalDisplayId();
+
+    //! Get token for a physical display given its stable ID
+    static sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId);
+    static sp<IBinder> getInternalDisplayToken();
 
     static status_t enableVSyncInjections(bool enable);
 
@@ -374,6 +378,7 @@
 #ifndef NO_INPUT
         Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
         Transaction& transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
+        Transaction& syncInputWindows();
 #endif
 
         // Set a color transform matrix on the given layer on the built-in display.
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index b584f36..55efcbf 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -58,8 +58,12 @@
     static bool isSameSurface(
             const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
 
-    // release surface data from java
-    void        clear();
+    // Release the handles assosciated with the SurfaceControl, without reparenting
+    // them off-screen. At the moment if this isn't executed before ~SurfaceControl
+    // is called then the destructor will reparent the layer off-screen for you.
+    void        release();
+    // Reparent off-screen and release. This is invoked by the destructor.
+    void destroy();
 
     // disconnect any api that's connected
     void        disconnect();
@@ -98,7 +102,6 @@
 
     sp<Surface> generateSurfaceLocked() const;
     status_t validate() const;
-    void destroy();
 
     sp<SurfaceComposerClient>   mClient;
     sp<IBinder>                 mHandle;
diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
index c92fa9d..c4d0245 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
@@ -57,7 +57,6 @@
 
 struct H2BGraphicBufferProducer : public ::android::H2BConverter<
         HGraphicBufferProducer,
-        BGraphicBufferProducer,
         BnGraphicBufferProducer> {
     explicit H2BGraphicBufferProducer(sp<HGraphicBufferProducer> const& base) : CBase(base) {}
 
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index f020a40..a5b87ec 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -87,3 +87,26 @@
         "libdvr_headers",
     ],
 }
+
+cc_test {
+    name: "SamplingDemo",
+
+    clang: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    srcs: [
+        "SamplingDemo.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libgui",
+        "liblog",
+        "libui",
+        "libutils",
+    ]
+}
diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp
index 5443812..b647aab 100644
--- a/libs/gui/tests/DisplayedContentSampling_test.cpp
+++ b/libs/gui/tests/DisplayedContentSampling_test.cpp
@@ -32,7 +32,7 @@
     void SetUp() {
         mComposerClient = new SurfaceComposerClient;
         ASSERT_EQ(OK, mComposerClient->initCheck());
-        mDisplayToken = mComposerClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+        mDisplayToken = mComposerClient->getInternalDisplayToken();
         ASSERT_TRUE(mDisplayToken);
     }
 
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index ac97733..4a78480 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -233,9 +233,11 @@
         mComposerClient = new SurfaceComposerClient;
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
 
+        const auto display = mComposerClient->getInternalDisplayToken();
+        ASSERT_FALSE(display == nullptr);
+
         DisplayInfo info;
-        auto display = mComposerClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
-        SurfaceComposerClient::getDisplayInfo(display, &info);
+        ASSERT_EQ(NO_ERROR, mComposerClient->getDisplayInfo(display, &info));
 
         // After a new buffer is queued, SurfaceFlinger is notified and will
         // latch the new buffer on next vsync.  Let's heuristically wait for 3
diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp
new file mode 100644
index 0000000..9891587
--- /dev/null
+++ b/libs/gui/tests/SamplingDemo.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#define LOG_TAG "SamplingTest"
+
+#include <chrono>
+#include <thread>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <gui/IRegionSamplingListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+#include <private/gui/ComposerService.h>
+#include <utils/Trace.h>
+
+using namespace std::chrono_literals;
+
+namespace android {
+
+class Button : public BnRegionSamplingListener {
+public:
+    Button(const char* name, const Rect& samplingArea) {
+        sp<SurfaceComposerClient> client = new SurfaceComposerClient;
+
+        mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888,
+                                        ISurfaceComposerClient::eFXSurfaceColor);
+
+        const int32_t width = samplingArea.getWidth();
+        const int32_t height = samplingArea.getHeight();
+
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mButton, 0x7fffffff)
+                .setCrop_legacy(mButton,
+                                {0, 0, width - 2 * BUTTON_PADDING, height - 2 * BUTTON_PADDING})
+                .setPosition(mButton, samplingArea.left + BUTTON_PADDING,
+                             samplingArea.top + BUTTON_PADDING)
+                .setColor(mButton, half3{1, 1, 1})
+                .show(mButton)
+                .apply();
+
+        mButtonBlend = client->createSurface(String8(name) + "Blend", 0, 0, PIXEL_FORMAT_RGBA_8888,
+                                             ISurfaceComposerClient::eFXSurfaceColor);
+
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mButtonBlend, 0x7ffffffe)
+                .setCrop_legacy(mButtonBlend,
+                                {0, 0, width - 2 * SAMPLE_AREA_PADDING,
+                                 height - 2 * SAMPLE_AREA_PADDING})
+                .setPosition(mButtonBlend, samplingArea.left + SAMPLE_AREA_PADDING,
+                             samplingArea.top + SAMPLE_AREA_PADDING)
+                .setColor(mButtonBlend, half3{1, 1, 1})
+                .setAlpha(mButtonBlend, 0.2)
+                .show(mButtonBlend)
+                .apply(true);
+
+        const bool HIGHLIGHT_SAMPLING_AREA = false;
+        if (HIGHLIGHT_SAMPLING_AREA) {
+            mSamplingArea =
+                    client->createSurface(String8("SamplingArea"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+                                          ISurfaceComposerClient::eFXSurfaceColor);
+
+            SurfaceComposerClient::Transaction{}
+                    .setLayer(mSamplingArea, 0x7ffffffd)
+                    .setCrop_legacy(mSamplingArea, {0, 0, 100, 32})
+                    .setPosition(mSamplingArea, 490, 1606)
+                    .setColor(mSamplingArea, half3{0, 1, 0})
+                    .setAlpha(mSamplingArea, 0.1)
+                    .show(mSamplingArea)
+                    .apply();
+        }
+    }
+
+    sp<IBinder> getStopLayerHandle() { return mButtonBlend->getHandle(); }
+
+private:
+    static const int32_t BLEND_WIDTH = 2;
+    static const int32_t SAMPLE_AREA_PADDING = 8;
+    static const int32_t BUTTON_PADDING = BLEND_WIDTH + SAMPLE_AREA_PADDING;
+
+    void setColor(float color) {
+        const float complement = std::fmod(color + 0.5f, 1.0f);
+        SurfaceComposerClient::Transaction{}
+                .setColor(mButton, half3{complement, complement, complement})
+                .setColor(mButtonBlend, half3{color, color, color})
+                .apply();
+    }
+
+    void onSampleCollected(float medianLuma) override {
+        ATRACE_CALL();
+        setColor(medianLuma);
+    }
+
+    sp<SurfaceComposerClient> mClient;
+    sp<SurfaceControl> mButton;
+    sp<SurfaceControl> mButtonBlend;
+    sp<SurfaceControl> mSamplingArea;
+};
+
+} // namespace android
+
+using namespace android;
+
+int main(int, const char**) {
+    const Rect homeButtonArea{490, 1606, 590, 1654};
+    sp<android::Button> homeButton = new android::Button("HomeButton", homeButtonArea);
+    const Rect backButtonArea{200, 1606, 248, 1654};
+    sp<android::Button> backButton = new android::Button("BackButton", backButtonArea);
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    composer->addRegionSamplingListener(homeButtonArea, homeButton->getStopLayerHandle(),
+                                        homeButton);
+    composer->addRegionSamplingListener(backButtonArea, backButton->getStopLayerHandle(),
+                                        backButton);
+
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+
+    return 0;
+}
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 8bd589d..f127853 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -131,8 +131,10 @@
 
     // Verify the screenshot works with no protected buffers.
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    sp<IBinder> display(sf->getBuiltInDisplay(
-            ISurfaceComposer::eDisplayIdMain));
+
+    const sp<IBinder> display = sf->getInternalDisplayToken();
+    ASSERT_FALSE(display == nullptr);
+
     sp<GraphicBuffer> outBuffer;
     ASSERT_EQ(NO_ERROR,
               sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB,
@@ -552,7 +554,8 @@
     sp<IBinder> createDisplay(const String8& /*displayName*/,
             bool /*secure*/) override { return nullptr; }
     void destroyDisplay(const sp<IBinder>& /*display */) override {}
-    sp<IBinder> getBuiltInDisplay(int32_t /*id*/) override { return nullptr; }
+    std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
+    sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
     void setTransactionState(const Vector<ComposerState>& /*state*/,
                              const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
                              const sp<IBinder>& /*applyToken*/,
@@ -666,6 +669,16 @@
 
     status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
 
+    status_t addRegionSamplingListener(const Rect& /*samplingArea*/,
+                                       const sp<IBinder>& /*stopLayerHandle*/,
+                                       const sp<IRegionSamplingListener>& /*listener*/) override {
+        return NO_ERROR;
+    }
+    status_t removeRegionSamplingListener(
+            const sp<IRegionSamplingListener>& /*listener*/) override {
+        return NO_ERROR;
+    }
+
 protected:
     IBinder* onAsBinder() override { return nullptr; }
 
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index fc676f1..2d78811 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -28,6 +28,7 @@
         "Keyboard.cpp",
         "KeyCharacterMap.cpp",
         "KeyLayoutMap.cpp",
+        "TouchVideoFrame.cpp",
         "VirtualKeyMap.cpp",
     ],
 
@@ -42,12 +43,13 @@
     target: {
         android: {
             srcs: [
+                "IInputFlinger.cpp",
+                "InputApplication.cpp",
                 "InputTransport.cpp",
+                "InputWindow.cpp",
+                "ISetInputWindowsListener.cpp",
                 "VelocityControl.cpp",
                 "VelocityTracker.cpp",
-                "InputApplication.cpp",
-                "InputWindow.cpp",
-                "IInputFlinger.cpp"
             ],
 
             shared_libs: [
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index acf40bc..4ce5a10 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -30,7 +30,8 @@
     explicit BpInputFlinger(const sp<IBinder>& impl) :
             BpInterface<IInputFlinger>(impl) { }
 
-    virtual void setInputWindows(const Vector<InputWindowInfo>& inputInfo) {
+    virtual void setInputWindows(const Vector<InputWindowInfo>& inputInfo,
+            const sp<ISetInputWindowsListener>& setInputWindowsListener) {
         Parcel data, reply;
         data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
 
@@ -38,6 +39,8 @@
         for (const auto& info : inputInfo) {
             info.write(data);
         }
+        data.writeStrongBinder(IInterface::asBinder(setInputWindowsListener));
+
         remote()->transact(BnInputFlinger::SET_INPUT_WINDOWS_TRANSACTION, data, &reply,
                 IBinder::FLAG_ONEWAY);
     }
@@ -83,7 +86,9 @@
         for (size_t i = 0; i < count; i++) {
             handles.add(InputWindowInfo(data));
         }
-        setInputWindows(handles);
+        const sp<ISetInputWindowsListener> setInputWindowsListener =
+                ISetInputWindowsListener::asInterface(data.readStrongBinder());
+        setInputWindows(handles, setInputWindowsListener);
         break;
     }
     case REGISTER_INPUT_CHANNEL_TRANSACTION: {
diff --git a/libs/input/ISetInputWindowsListener.cpp b/libs/input/ISetInputWindowsListener.cpp
new file mode 100644
index 0000000..a0330da
--- /dev/null
+++ b/libs/input/ISetInputWindowsListener.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#include <input/ISetInputWindowsListener.h>
+
+namespace android {
+
+class BpSetInputWindowsListener : public BpInterface<ISetInputWindowsListener> {
+public:
+    explicit BpSetInputWindowsListener(const sp<IBinder>& impl)
+        : BpInterface<ISetInputWindowsListener>(impl) {
+    }
+
+    virtual ~BpSetInputWindowsListener() = default;
+
+    virtual void onSetInputWindowsFinished() {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISetInputWindowsListener::getInterfaceDescriptor());
+        remote()->transact(BnSetInputWindowsListener::ON_SET_INPUT_WINDOWS_FINISHED, data, &reply,
+                IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(SetInputWindowsListener, "android.input.ISetInputWindowsListener");
+
+status_t BnSetInputWindowsListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+        uint32_t flags) {
+    switch(code) {
+        case ON_SET_INPUT_WINDOWS_FINISHED: {
+            CHECK_INTERFACE(ISetInputWindowsListener, data, reply);
+            onSetInputWindowsFinished();
+            return NO_ERROR;
+        }
+        default: {
+            return BBinder::onTransact(code, data, reply, flags);
+        }
+    }
+}
+
+} // namespace android
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 778c453..dab6eac 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -46,15 +46,9 @@
 
 static void appendInputDeviceConfigurationFileRelativePath(std::string& path,
         const std::string& name, InputDeviceConfigurationFileType type) {
-    path.append(CONFIGURATION_FILE_DIR[type]);
-    for (size_t i = 0; i < name.length(); i++) {
-        char ch = name[i];
-        if (!isValidNameChar(ch)) {
-            ch = '_';
-        }
-        path.append(&ch, 1);
-    }
-    path.append(CONFIGURATION_FILE_EXTENSION[type]);
+    path += CONFIGURATION_FILE_DIR[type];
+    path += name;
+    path += CONFIGURATION_FILE_EXTENSION[type];
 }
 
 std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
@@ -84,7 +78,7 @@
     }
 
     // Try device name.
-    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
+    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName(), type);
 }
 
 std::string getInputDeviceConfigurationFilePathByName(
@@ -140,6 +134,18 @@
     return "";
 }
 
+// --- InputDeviceIdentifier
+
+std::string InputDeviceIdentifier::getCanonicalName() const {
+    std::string replacedName = name;
+    for (char& ch : replacedName) {
+        if (!isValidNameChar(ch)) {
+            ch = '_';
+        }
+    }
+    return replacedName;
+}
+
 
 // --- InputDeviceInfo ---
 
diff --git a/libs/input/TouchVideoFrame.cpp b/libs/input/TouchVideoFrame.cpp
new file mode 100644
index 0000000..8a4298a
--- /dev/null
+++ b/libs/input/TouchVideoFrame.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#include <input/TouchVideoFrame.h>
+
+namespace android {
+
+TouchVideoFrame::TouchVideoFrame(uint32_t height, uint32_t width, std::vector<int16_t> data,
+        const struct timeval& timestamp) :
+         mHeight(height), mWidth(width),mData(std::move(data)), mTimestamp(timestamp) {
+}
+
+bool TouchVideoFrame::operator==(const TouchVideoFrame& rhs) const {
+    return mHeight == rhs.mHeight
+            && mWidth == rhs.mWidth
+            && mData == rhs.mData
+            && mTimestamp.tv_sec == rhs.mTimestamp.tv_sec
+            && mTimestamp.tv_usec == rhs.mTimestamp.tv_usec;
+}
+
+uint32_t TouchVideoFrame::getHeight() const { return mHeight; }
+
+uint32_t TouchVideoFrame::getWidth() const { return mWidth; }
+
+const std::vector<int16_t>& TouchVideoFrame::getData() const { return mData; }
+
+const struct timeval& TouchVideoFrame::getTimestamp() const { return mTimestamp; }
+
+void TouchVideoFrame::rotate(int32_t orientation) {
+    switch (orientation) {
+        case DISPLAY_ORIENTATION_90:
+            rotateQuarterTurn(true /*clockwise*/);
+            break;
+        case DISPLAY_ORIENTATION_180:
+            rotate180();
+            break;
+        case DISPLAY_ORIENTATION_270:
+            rotateQuarterTurn(false /*clockwise*/);
+            break;
+    }
+}
+
+/**
+ * Rotate once clockwise by a quarter turn === rotate 90 degrees
+ * Rotate once counterclockwise by a quarter turn === rotate 270 degrees
+ * For a clockwise rotation:
+ *     An element at position (i, j) is rotated to (j, height - i - 1)
+ * For a counterclockwise rotation:
+ *     An element at position (i, j) is rotated to (width - j - 1, i)
+ */
+void TouchVideoFrame::rotateQuarterTurn(bool clockwise) {
+    std::vector<int16_t> rotated(mData.size());
+    for (size_t i = 0; i < mHeight; i++) {
+        for (size_t j = 0; j < mWidth; j++) {
+            size_t iRotated, jRotated;
+            if (clockwise) {
+                iRotated = j;
+                jRotated = mHeight - i - 1;
+            } else {
+                iRotated = mWidth - j - 1;
+                jRotated = i;
+            }
+            size_t indexRotated = iRotated * mHeight + jRotated;
+            rotated[indexRotated] = mData[i * mWidth + j];
+        }
+    }
+    mData = std::move(rotated);
+    std::swap(mHeight, mWidth);
+}
+
+/**
+ * An element at position (i, j) is rotated to (height - i - 1, width - j - 1)
+ * This is equivalent to moving element [i] to position [height * width - i - 1]
+ * Since element at [height * width - i - 1] would move to position [i],
+ * we can just swap elements [i] and [height * width - i - 1].
+ */
+void TouchVideoFrame::rotate180() {
+    if (mData.size() == 0) {
+        return;
+    }
+    // Just need to swap elements i and (height * width - 1 - i)
+    for (size_t i = 0; i < mData.size() / 2; i++) {
+        std::swap(mData[i], mData[mHeight * mWidth - 1 - i]);
+    }
+}
+
+} // namespace android
diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp
index 3ec53bf..624f152 100644
--- a/libs/input/VirtualKeyMap.cpp
+++ b/libs/input/VirtualKeyMap.cpp
@@ -28,10 +28,6 @@
 // Enables debug output for the parser.
 #define DEBUG_PARSER 0
 
-// Enables debug output for parser performance.
-#define DEBUG_PARSER_PERFORMANCE 0
-
-
 namespace android {
 
 static const char* WHITESPACE = " \t\r";
@@ -46,39 +42,28 @@
 VirtualKeyMap::~VirtualKeyMap() {
 }
 
-status_t VirtualKeyMap::load(const std::string& filename, VirtualKeyMap** outMap) {
-    *outMap = nullptr;
-
-    Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
-    if (status) {
+std::unique_ptr<VirtualKeyMap> VirtualKeyMap::load(const std::string& filename) {
+    Tokenizer* t;
+    status_t status = Tokenizer::open(String8(filename.c_str()), &t);
+    if (status != OK) {
         ALOGE("Error %d opening virtual key map file %s.", status, filename.c_str());
-    } else {
-        VirtualKeyMap* map = new VirtualKeyMap();
-        if (!map) {
-            ALOGE("Error allocating virtual key map.");
-            status = NO_MEMORY;
-        } else {
-#if DEBUG_PARSER_PERFORMANCE
-            nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
-            Parser parser(map, tokenizer);
-            status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
-            nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
-            ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
-                    tokenizer->getFilename().string(), tokenizer->getLineNumber(),
-                    elapsedTime / 1000000.0);
-#endif
-            if (status) {
-                delete map;
-            } else {
-                *outMap = map;
-            }
-        }
-        delete tokenizer;
+        return nullptr;
     }
-    return status;
+    std::unique_ptr<Tokenizer> tokenizer(t);
+    // Using 'new' to access a non-public constructor
+    std::unique_ptr<VirtualKeyMap> map(new VirtualKeyMap());
+    if (!map) {
+        ALOGE("Error allocating virtual key map.");
+        return nullptr;
+    }
+
+    Parser parser(map.get(), tokenizer.get());
+    status = parser.parse();
+    if (status != OK) {
+        return nullptr;
+    }
+
+    return map;
 }
 
 
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index fdd945e..57ba2a2 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -5,8 +5,9 @@
         "InputChannel_test.cpp",
         "InputEvent_test.cpp",
         "InputPublisherAndConsumer_test.cpp",
+        "InputWindow_test.cpp",
+        "TouchVideoFrame_test.cpp",
         "VelocityTracker_test.cpp",
-        "InputWindow_test.cpp"
     ],
     cflags: [
         "-Wall",
diff --git a/libs/input/tests/TouchVideoFrame_test.cpp b/libs/input/tests/TouchVideoFrame_test.cpp
new file mode 100644
index 0000000..815424e
--- /dev/null
+++ b/libs/input/tests/TouchVideoFrame_test.cpp
@@ -0,0 +1,196 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <input/TouchVideoFrame.h>
+
+namespace android {
+namespace test {
+
+static const struct timeval TIMESTAMP = {1, 2};
+
+TEST(TouchVideoFrame, Constructor) {
+    const std::vector<int16_t> data = {1, 2, 3, 4, 5, 6};
+    constexpr uint32_t height = 3;
+    constexpr uint32_t width = 2;
+
+    TouchVideoFrame frame(height, width, data, TIMESTAMP);
+
+    ASSERT_EQ(data, frame.getData());
+    ASSERT_EQ(height, frame.getHeight());
+    ASSERT_EQ(width, frame.getWidth());
+    ASSERT_EQ(TIMESTAMP.tv_sec, frame.getTimestamp().tv_sec);
+    ASSERT_EQ(TIMESTAMP.tv_usec, frame.getTimestamp().tv_usec);
+}
+
+TEST(TouchVideoFrame, Equality) {
+    const std::vector<int16_t> data = {1, 2, 3, 4, 5, 6};
+    constexpr uint32_t height = 3;
+    constexpr uint32_t width = 2;
+    TouchVideoFrame frame(height, width, data, TIMESTAMP);
+
+    TouchVideoFrame identicalFrame(height, width, data, TIMESTAMP);
+    ASSERT_EQ(frame, identicalFrame);
+
+    // The two cases below create an invalid frame, but it is OK for comparison purposes.
+    // There aren't any checks currently enforced on the frame dimensions and data
+    // Change height
+    TouchVideoFrame changedHeightFrame(height + 1, width, data, TIMESTAMP);
+    ASSERT_FALSE(frame == changedHeightFrame);
+
+    // Change width
+    TouchVideoFrame changedWidthFrame(height, width + 1, data, TIMESTAMP);
+    ASSERT_FALSE(frame == changedWidthFrame);
+
+    // Change data
+    const std::vector<int16_t> differentData = {1, 2, 3, 3, 5, 6};
+    TouchVideoFrame changedDataFrame(height, width, differentData, TIMESTAMP);
+    ASSERT_FALSE(frame == changedDataFrame);
+
+    // Change timestamp
+    const struct timeval differentTimestamp = {TIMESTAMP.tv_sec + 1, TIMESTAMP.tv_usec + 1};
+    TouchVideoFrame changedTimestampFrame(height, width, data, differentTimestamp);
+    ASSERT_FALSE(frame == changedTimestampFrame);
+}
+
+// --- Rotate 90 degrees ---
+
+TEST(TouchVideoFrame, Rotate90_0x0) {
+    TouchVideoFrame frame(0, 0, {}, TIMESTAMP);
+    TouchVideoFrame frameRotated(0, 0, {}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate90_1x1) {
+    TouchVideoFrame frame(1, 1, {1}, TIMESTAMP);
+    TouchVideoFrame frameRotated(1, 1, {1}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate90_2x2) {
+    TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP);
+    TouchVideoFrame frameRotated(2, 2, {3, 1, 4, 2}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate90_3x2) {
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    TouchVideoFrame frameRotated(2, 3, {5, 3, 1, 6, 4, 2}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate90_3x2_4times) {
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    TouchVideoFrame frameOriginal(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    ASSERT_EQ(frame, frameOriginal);
+}
+
+// --- Rotate 180 degrees ---
+
+TEST(TouchVideoFrame, Rotate180_0x0) {
+    TouchVideoFrame frame(0, 0, {}, TIMESTAMP);
+    TouchVideoFrame frameRotated(0, 0, {}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate180_1x1) {
+    TouchVideoFrame frame(1, 1, {1}, TIMESTAMP);
+    TouchVideoFrame frameRotated(1, 1, {1}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate180_2x2) {
+    TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP);
+    TouchVideoFrame frameRotated(2, 2, {4, 3, 2, 1}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate180_3x2) {
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    TouchVideoFrame frameRotated(3, 2, {6, 5, 4, 3, 2, 1}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate180_3x2_2times) {
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    TouchVideoFrame frameOriginal(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    ASSERT_EQ(frame, frameOriginal);
+}
+
+TEST(TouchVideoFrame, Rotate180_3x3) {
+    TouchVideoFrame frame(3, 3, {1, 2, 3, 4, 5, 6, 7, 8, 9}, TIMESTAMP);
+    TouchVideoFrame frameRotated(3, 3, {9, 8, 7, 6, 5, 4, 3, 2, 1}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+// --- Rotate 270 degrees ---
+
+TEST(TouchVideoFrame, Rotate270_0x0) {
+    TouchVideoFrame frame(0, 0, {}, TIMESTAMP);
+    TouchVideoFrame frameRotated(0, 0, {}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate270_1x1) {
+    TouchVideoFrame frame(1, 1, {1}, TIMESTAMP);
+    TouchVideoFrame frameRotated(1, 1, {1}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate270_2x2) {
+    TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP);
+    TouchVideoFrame frameRotated(2, 2, {2, 4, 1, 3}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate270_3x2) {
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    TouchVideoFrame frameRotated(2, 3, {2, 4, 6, 1, 3, 5}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate270_3x2_4times) {
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    TouchVideoFrame frameOriginal(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    ASSERT_EQ(frame, frameOriginal);
+}
+
+} // namespace test
+} // namespace android
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 6ea1270..994e953 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -122,6 +122,54 @@
     return gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence);
 }
 
+int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage,
+        int32_t fence, const ARect* rect, AHardwareBuffer_Planes* outPlanes) {
+    if (!buffer || !outPlanes) return BAD_VALUE;
+
+    if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
+                  AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) {
+        ALOGE("Invalid usage flags passed to AHardwareBuffer_lock; only "
+                " AHARDWAREBUFFER_USAGE_CPU_* flags are allowed");
+        return BAD_VALUE;
+    }
+
+    usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
+    GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+    Rect bounds;
+    if (!rect) {
+        bounds.set(Rect(gBuffer->getWidth(), gBuffer->getHeight()));
+    } else {
+        bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
+    }
+    int format = AHardwareBuffer_convertFromPixelFormat(uint32_t(gBuffer->getPixelFormat()));
+    memset(outPlanes->planes, 0, sizeof(outPlanes->planes));
+    if (AHardwareBuffer_formatIsYuv(format)) {
+      android_ycbcr yuvData;
+      int result = gBuffer->lockAsyncYCbCr(usage, bounds, &yuvData, fence);
+      if (result == 0) {
+        outPlanes->planeCount = 3;
+        outPlanes->planes[0].data = yuvData.y;
+        outPlanes->planes[0].pixelStride = 1;
+        outPlanes->planes[0].rowStride = yuvData.ystride;
+        outPlanes->planes[1].data = yuvData.cb;
+        outPlanes->planes[1].pixelStride = yuvData.chroma_step;
+        outPlanes->planes[1].rowStride = yuvData.cstride;
+        outPlanes->planes[2].data = yuvData.cr;
+        outPlanes->planes[2].pixelStride = yuvData.chroma_step;
+        outPlanes->planes[2].rowStride = yuvData.cstride;
+      } else {
+        outPlanes->planeCount = 0;
+      }
+      return result;
+    } else {
+      const uint32_t pixelStride = AHardwareBuffer_bytesPerPixel(format);
+      outPlanes->planeCount = 1;
+      outPlanes->planes[0].pixelStride = pixelStride;
+      outPlanes->planes[0].rowStride = gBuffer->getStride() * pixelStride;
+      return gBuffer->lockAsync(usage, usage, bounds, &outPlanes->planes[0].data, fence);
+    }
+}
+
 int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) {
     if (!buffer) return BAD_VALUE;
 
@@ -263,8 +311,17 @@
     if (!desc) return 0;
     if (!AHardwareBuffer_isValidDescription(desc, /*log=*/false)) return 0;
 
-    // Make a trial allocation.
-    // TODO(b/115660272): add implementation that uses a HAL query.
+    bool supported = false;
+    GraphicBuffer* gBuffer = new GraphicBuffer();
+    status_t err = gBuffer->isSupported(desc->width, desc->height, desc->format, desc->layers,
+                                        desc->usage, &supported);
+
+    if (err == NO_ERROR) {
+        return supported;
+    }
+
+    // function isSupported is not implemented on device or an error occurred during HAL
+    // query.  Make a trial allocation.
     AHardwareBuffer_Desc trialDesc = *desc;
     trialDesc.width = 4;
     trialDesc.height = desc->format == AHARDWAREBUFFER_FORMAT_BLOB ? 1 : 4;
@@ -366,6 +423,19 @@
             ALOGE_IF(log, "AHARDWAREBUFFER_FORMAT_BLOB cannot be encoded as video");
             return false;
         }
+    } else if (AHardwareBuffer_formatIsYuv(desc->format)) {
+        if (desc->layers != 1) {
+            ALOGE_IF(log, "Layers must be 1 for YUV formats.");
+            return false;
+        }
+        const uint64_t yuvInvalidGpuMask =
+            AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE |
+            AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP;
+        if (desc->usage & yuvInvalidGpuMask) {
+            ALOGE_IF(log, "Invalid usage flags specified for YUV format; "
+                    "mip-mapping and cube-mapping are not allowed.");
+            return false;
+        }
     } else {
         if (desc->usage & AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA) {
             ALOGE_IF(log, "AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA requires AHARDWAREBUFFER_FORMAT_BLOB");
@@ -465,6 +535,7 @@
         case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
         case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
         case AHARDWAREBUFFER_FORMAT_S8_UINT:
+        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
             // VNDK formats only -- unfortunately we can't differentiate from where we're called
         case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM:
         case AHARDWAREBUFFER_FORMAT_YV12:
@@ -475,7 +546,6 @@
         case AHARDWAREBUFFER_FORMAT_RAW12:
         case AHARDWAREBUFFER_FORMAT_RAW_OPAQUE:
         case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED:
-        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
         case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
@@ -486,6 +556,40 @@
     }
 }
 
+bool AHardwareBuffer_formatIsYuv(uint32_t format) {
+    switch (format) {
+        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
+        case AHARDWAREBUFFER_FORMAT_YV12:
+        case AHARDWAREBUFFER_FORMAT_Y8:
+        case AHARDWAREBUFFER_FORMAT_Y16:
+        case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
+        case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
+        case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
+            return true;
+        default:
+            return false;
+    }
+}
+
+uint32_t AHardwareBuffer_bytesPerPixel(uint32_t format) {
+  switch (format) {
+      case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
+      case AHARDWAREBUFFER_FORMAT_D16_UNORM:
+          return 2;
+      case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+      case AHARDWAREBUFFER_FORMAT_D24_UNORM:
+          return 3;
+      case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
+      case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
+      case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
+      case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+      case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
+          return 4;
+      default:
+          return 0;
+  }
+}
+
 uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t hal_format) {
     return hal_format;
 }
diff --git a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
index bf688f8..ddfd1d1 100644
--- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
+++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
@@ -40,6 +40,12 @@
 // whether this AHardwareBuffer format is valid
 bool AHardwareBuffer_isValidPixelFormat(uint32_t ahardwarebuffer_format);
 
+// whether this is a YUV type format
+bool AHardwareBuffer_formatIsYuv(uint32_t format);
+
+// number of bytes per pixel or 0 if unknown or multi-planar
+uint32_t AHardwareBuffer_bytesPerPixel(uint32_t format);
+
 // convert AHardwareBuffer format to HAL format (note: this is a no-op)
 uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format);
 
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 2796c75..02c7c1b 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -150,6 +150,14 @@
      *   OpenGL ES: GL_STENCIL_INDEX8
      */
     AHARDWAREBUFFER_FORMAT_S8_UINT                  = 0x35,
+
+    /**
+     * YUV 420 888 format.
+     * Must have an even width and height. Can be accessed in OpenGL
+     * shaders through an external sampler. Does not support mip-maps
+     * cube-maps or multi-layered textures.
+     */
+    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420             = 0x23,
 };
 
 /**
@@ -302,6 +310,24 @@
 } AHardwareBuffer_Desc;
 
 /**
+ * Holds data for a single image plane.
+ */
+typedef struct AHardwareBuffer_Plane {
+    void*       data;        ///< Points to first byte in plane
+    uint32_t    pixelStride; ///< Distance in bytes from the color channel of one pixel to the next
+    uint32_t    rowStride;   ///< Distance in bytes from the first value of one row of the image to
+                             ///  the first value of the next row.
+} AHardwareBuffer_Plane;
+
+/**
+ * Holds all image planes that contain the pixel data.
+ */
+typedef struct AHardwareBuffer_Planes {
+    uint32_t               planeCount; ///< Number of distinct planes
+    AHardwareBuffer_Plane  planes[4];     ///< Array of image planes
+} AHardwareBuffer_Planes;
+
+/**
  * Opaque handle for a native hardware buffer.
  */
 typedef struct AHardwareBuffer AHardwareBuffer;
@@ -323,7 +349,7 @@
         AHardwareBuffer** outBuffer) __INTRODUCED_IN(26);
 /**
  * Acquire a reference on the given AHardwareBuffer object.
- * 
+ *
  * This prevents the object from being deleted until the last reference
  * is removed.
  */
@@ -396,6 +422,34 @@
         int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26);
 
 /**
+ * Lock a potentially multi-planar AHardwareBuffer for direct CPU access.
+ *
+ * This function is similar to AHardwareBuffer_lock, but can lock multi-planar
+ * formats. The locked planes are returned in the \a outPlanes argument. Note,
+ * that multi-planar should not be confused with multi-layer images, which this
+ * locking function does not support.
+ *
+ * YUV formats are always represented by three separate planes of data, one for
+ * each color plane. The order of planes in the array is guaranteed such that
+ * plane #0 is always Y, plane #1 is always U (Cb), and plane #2 is always V
+ * (Cr). All other formats are represented by a single plane.
+ *
+ * Additional information always accompanies the buffers, describing the row
+ * stride and the pixel stride for each plane.
+ *
+ * In case the buffer cannot be locked, \a outPlanes will contain zero planes.
+ *
+ * See the AHardwareBuffer_lock documentation for all other locking semantics.
+ *
+ * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags
+ * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer
+ * has more than one layer. Error number if the lock fails for any other
+ * reason.
+ */
+int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage,
+        int32_t fence, const ARect* rect, AHardwareBuffer_Planes* outPlanes) __INTRODUCED_IN(29);
+
+/**
  * Unlock the AHardwareBuffer from direct CPU access.
  *
  * Must be called after all changes to the buffer are completed by the
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index 6c9ec34..3392d7f 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -73,8 +73,6 @@
     AHARDWAREBUFFER_FORMAT_RAW_OPAQUE               = 0x24,
     /* same as HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED */
     AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED   = 0x22,
-    /* same as HAL_PIXEL_FORMAT_YCBCR_420_888 */
-    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420             = 0x23,
     /* same as HAL_PIXEL_FORMAT_YCBCR_422_SP */
     AHARDWAREBUFFER_FORMAT_YCbCr_422_SP             = 0x10,
     /* same as HAL_PIXEL_FORMAT_YCRCB_420_SP */
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
new file mode 100644
index 0000000..c00fbba
--- /dev/null
+++ b/libs/renderengine/OWNERS
@@ -0,0 +1,2 @@
+lpy@google.com
+stoza@google.com
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index c5a9942..e7ff9ab 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -424,6 +424,7 @@
         mTraceGpuCompletion = true;
         mFlushTracer = std::make_unique<FlushTracer>(this);
     }
+    mDrawingBuffer = createFramebuffer();
 }
 
 GLESRenderEngine::~GLESRenderEngine() {
@@ -439,6 +440,10 @@
     return std::make_unique<GLImage>(*this);
 }
 
+Framebuffer* GLESRenderEngine::getFramebufferForDrawing() {
+    return mDrawingBuffer.get();
+}
+
 void GLESRenderEngine::primeCache() const {
     ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext,
                                            mFeatureFlags & USE_COLOR_MANAGEMENT);
@@ -449,6 +454,7 @@
 }
 
 base::unique_fd GLESRenderEngine::flush() {
+    ATRACE_CALL();
     if (!GLExtensions::getInstance().hasNativeFenceSync()) {
         return base::unique_fd();
     }
@@ -479,6 +485,7 @@
 }
 
 bool GLESRenderEngine::finish() {
+    ATRACE_CALL();
     if (!GLExtensions::getInstance().hasFenceSync()) {
         ALOGW("no synchronization support");
         return false;
@@ -544,6 +551,8 @@
 }
 
 void GLESRenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
+    ATRACE_CALL();
+    glDisable(GL_BLEND);
     glClearColor(red, green, blue, alpha);
     glClear(GL_COLOR_BUFFER_BIT);
 }
@@ -594,6 +603,7 @@
 }
 
 void GLESRenderEngine::bindExternalTextureImage(uint32_t texName, const Image& image) {
+    ATRACE_CALL();
     const GLImage& glImage = static_cast<const GLImage&>(image);
     const GLenum target = GL_TEXTURE_EXTERNAL_OES;
 
@@ -608,8 +618,15 @@
 }
 
 status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
+                                                     sp<Fence> bufferFence, bool readCache) {
+    return bindExternalTextureBuffer(texName, buffer, bufferFence, readCache,
+                                     /*persistCache=*/false);
+}
+
+status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
                                                      sp<Fence> bufferFence, bool readCache,
                                                      bool persistCache) {
+    ATRACE_CALL();
     if (readCache) {
         auto cachedImage = mImageCache.find(buffer->getId());
 
@@ -655,7 +672,7 @@
     }
 
     // We don't always want to persist to the cache, e.g. on older devices we
-    // might bind for synchronization purpoeses, but that might leak if we never
+    // might bind for synchronization purposes, but that might leak if we never
     // call drawLayers again, so it's just better to recreate the image again
     // if needed when we draw.
     if (persistCache) {
@@ -666,6 +683,7 @@
 }
 
 void GLESRenderEngine::evictImages(const std::vector<LayerSettings>& layers) {
+    ATRACE_CALL();
     // destroy old image references that we're not going to draw with.
     std::unordered_set<uint64_t> bufIds;
     for (auto layer : layers) {
@@ -703,6 +721,7 @@
 }
 
 status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
+    ATRACE_CALL();
     GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
     EGLImageKHR eglImage = glFramebuffer->getEGLImage();
     uint32_t textureName = glFramebuffer->getTextureName();
@@ -731,6 +750,7 @@
 }
 
 void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
+    ATRACE_CALL();
     mFboHeight = 0;
 
     // back to main framebuffer
@@ -769,12 +789,18 @@
 status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
                                       const std::vector<LayerSettings>& layers,
                                       ANativeWindowBuffer* const buffer,
-                                      base::unique_fd* drawFence) {
+                                      base::unique_fd&& bufferFence, base::unique_fd* drawFence) {
+    ATRACE_CALL();
     if (layers.empty()) {
         ALOGV("Drawing empty layer stack");
         return NO_ERROR;
     }
 
+    if (bufferFence.get() >= 0 && !waitFence(std::move(bufferFence))) {
+        ATRACE_NAME("Waiting before draw");
+        sync_wait(bufferFence.get(), -1);
+    }
+
     BindNativeBufferAsFramebuffer fbo(*this, buffer);
 
     if (fbo.getStatus() != NO_ERROR) {
@@ -786,6 +812,13 @@
 
     evictImages(layers);
 
+    // clear the entire buffer, sometimes when we reuse buffers we'd persist
+    // ghost images otherwise.
+    // we also require a full transparent framebuffer for overlays. This is
+    // probably not quite efficient on all GPUs, since we could filter out
+    // opaque layers.
+    clearWithColor(0.0, 0.0, 0.0, 0.0);
+
     setViewportAndProjection(display.physicalDisplay, display.clip);
 
     setOutputDataSpace(display.outputDataspace);
@@ -794,6 +827,7 @@
     mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform;
     mState.projectionMatrix = projectionMatrix;
     if (!display.clearRegion.isEmpty()) {
+        glDisable(GL_BLEND);
         fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0);
     }
 
@@ -813,9 +847,11 @@
 
         bool usePremultipliedAlpha = true;
         bool disableTexture = true;
+        bool isOpaque = false;
 
         if (layer.source.buffer.buffer != nullptr) {
             disableTexture = false;
+            isOpaque = layer.source.buffer.isOpaque;
 
             sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
 
@@ -825,17 +861,19 @@
 
             usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
             Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
-            texture.setMatrix(layer.source.buffer.textureTransform.asArray());
+            mat4 texMatrix = layer.source.buffer.textureTransform;
+
+            texture.setMatrix(texMatrix.asArray());
             texture.setFiltering(layer.source.buffer.useTextureFiltering);
 
             texture.setDimensions(gBuf->getWidth(), gBuf->getHeight());
             setSourceY410BT2020(layer.source.buffer.isY410BT2020);
 
             renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
-            texCoords[0] = vec2(0.0, 1.0);
-            texCoords[1] = vec2(0.0, 0.0);
-            texCoords[2] = vec2(1.0, 0.0);
-            texCoords[3] = vec2(1.0, 1.0);
+            texCoords[0] = vec2(0.0, 0.0);
+            texCoords[1] = vec2(0.0, 1.0);
+            texCoords[2] = vec2(1.0, 1.0);
+            texCoords[3] = vec2(1.0, 0.0);
             setupLayerTexturing(texture);
         }
 
@@ -843,8 +881,11 @@
         const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
         // Buffer sources will have a black solid color ignored in the shader,
         // so in that scenario the solid color passed here is arbitrary.
-        setupLayerBlending(usePremultipliedAlpha, layer.source.buffer.isOpaque, disableTexture,
-                           color, layer.geometry.roundedCornersRadius);
+        setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color,
+                           layer.geometry.roundedCornersRadius);
+        if (layer.disableBlending) {
+            glDisable(GL_BLEND);
+        }
         setSourceDataSpace(layer.sourceDataspace);
 
         drawMesh(mesh);
@@ -903,6 +944,7 @@
 }
 
 void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) {
+    ATRACE_CALL();
     mVpWidth = viewport.getWidth();
     mVpHeight = viewport.getHeight();
 
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index e094860..a86b4f5 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -71,6 +71,8 @@
     void genTextures(size_t count, uint32_t* names) override;
     void deleteTextures(size_t count, uint32_t const* names) override;
     void bindExternalTextureImage(uint32_t texName, const Image& image) override;
+    status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence,
+                                       bool readCache);
     status_t bindFrameBuffer(Framebuffer* framebuffer) override;
     void unbindFrameBuffer(Framebuffer* framebuffer) override;
     void checkErrors() const override;
@@ -79,13 +81,15 @@
     bool supportsProtectedContent() const override;
     bool useProtectedContext(bool useProtectedContext) override;
     status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers,
-                        ANativeWindowBuffer* buffer, base::unique_fd* drawFence) override;
+                        ANativeWindowBuffer* buffer, base::unique_fd&& bufferFence,
+                        base::unique_fd* drawFence) override;
 
     // internal to RenderEngine
     EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
     EGLConfig getEGLConfig() const { return mEGLConfig; }
 
 protected:
+    Framebuffer* getFramebufferForDrawing() override;
     void dump(std::string& result) override;
     void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
                                   ui::Transform::orientation_flags rotation) override;
@@ -184,8 +188,13 @@
     const bool mUseColorManagement = false;
 
     // Cache of GL images that we'll store per GraphicBuffer ID
+    // TODO: Layer should call back on destruction instead to clean this up,
+    // as it has better system utilization at the potential expense of a
+    // more complicated interface.
     std::unordered_map<uint64_t, std::unique_ptr<Image>> mImageCache;
 
+    std::unique_ptr<Framebuffer> mDrawingBuffer;
+
     class FlushTracer {
     public:
         FlushTracer(GLESRenderEngine* engine);
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index 4a519bb..0e3b405 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include "GLFramebuffer.h"
 
 #include <GLES/gl.h>
@@ -21,6 +23,7 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <nativebase/nativebase.h>
+#include <utils/Trace.h>
 #include "GLESRenderEngine.h"
 
 namespace android {
@@ -40,6 +43,7 @@
 }
 
 bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) {
+    ATRACE_CALL();
     if (mEGLImage != EGL_NO_IMAGE_KHR) {
         eglDestroyImageKHR(mEGLDisplay, mEGLImage);
         mEGLImage = EGL_NO_IMAGE_KHR;
diff --git a/libs/renderengine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp
index 587cb31..77e648e 100644
--- a/libs/renderengine/gl/GLImage.cpp
+++ b/libs/renderengine/gl/GLImage.cpp
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include "GLImage.h"
 
 #include <vector>
 
 #include <log/log.h>
+#include <utils/Trace.h>
 #include "GLESRenderEngine.h"
 #include "GLExtensions.h"
 
@@ -50,6 +53,7 @@
 }
 
 bool GLImage::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) {
+    ATRACE_CALL();
     if (mEGLImage != EGL_NO_IMAGE_KHR) {
         if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
             ALOGE("failed to destroy image: %#x", eglGetError());
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 56ac714..aa45ed8 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -126,6 +126,9 @@
     // Additional layer-specific color transform to be applied before the global
     // transform.
     mat4 colorTransform = mat4();
+
+    // True if blending will be forced to be disabled.
+    bool disableBlending = false;
 };
 
 } // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 20dd996..812d761 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -108,6 +108,8 @@
     virtual void genTextures(size_t count, uint32_t* names) = 0;
     virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
     virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
+    virtual status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
+                                               sp<Fence> fence, bool cleanCache) = 0;
     // When binding a native buffer, it must be done before setViewportAndProjection
     // Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
     virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0;
@@ -165,44 +167,47 @@
     // drawing any layers.
     // @param layers The layers to draw onto the display, in Z-order.
     // @param buffer The buffer which will be drawn to. This buffer will be
-    // ready once displayFence fires.
+    // ready once drawFence fires.
+    // @param bufferFence Fence signalling that the buffer is ready to be drawn
+    // to.
     // @param drawFence A pointer to a fence, which will fire when the buffer
     // has been drawn to and is ready to be examined. The fence will be
     // initialized by this method. The caller will be responsible for owning the
     // fence.
     // @return An error code indicating whether drawing was successful. For
     // now, this always returns NO_ERROR.
-    // TODO(alecmouri): Consider making this a multi-display API, so that the
-    // caller deoes not need to handle multiple fences.
     virtual status_t drawLayers(const DisplaySettings& display,
                                 const std::vector<LayerSettings>& layers,
-                                ANativeWindowBuffer* buffer, base::unique_fd* drawFence) = 0;
+                                ANativeWindowBuffer* buffer, base::unique_fd&& bufferFence,
+                                base::unique_fd* drawFence) = 0;
 
-    // TODO(alecmouri): Expose something like bindTexImage() so that devices
-    // that don't support native sync fences can get rid of code duplicated
-    // between BufferStateLayer and BufferQueueLayer for binding an external
-    // texture.
-
-    // TODO(alecmouri): Add API to help with managing a texture pool.
+protected:
+    // Gets a framebuffer to render to. This framebuffer may or may not be
+    // cached depending on the implementation.
+    //
+    // Note that this method does not transfer ownership, so the caller most not
+    // live longer than RenderEngine.
+    virtual Framebuffer* getFramebufferForDrawing() = 0;
+    friend class BindNativeBufferAsFramebuffer;
 };
 
 class BindNativeBufferAsFramebuffer {
 public:
     BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer)
-          : mEngine(engine), mFramebuffer(mEngine.createFramebuffer()), mStatus(NO_ERROR) {
+          : mEngine(engine), mFramebuffer(mEngine.getFramebufferForDrawing()), mStatus(NO_ERROR) {
         mStatus = mFramebuffer->setNativeWindowBuffer(buffer, mEngine.isProtected())
-                ? mEngine.bindFrameBuffer(mFramebuffer.get())
+                ? mEngine.bindFrameBuffer(mFramebuffer)
                 : NO_MEMORY;
     }
     ~BindNativeBufferAsFramebuffer() {
         mFramebuffer->setNativeWindowBuffer(nullptr, false);
-        mEngine.unbindFrameBuffer(mFramebuffer.get());
+        mEngine.unbindFrameBuffer(mFramebuffer);
     }
     status_t getStatus() const { return mStatus; }
 
 private:
     RenderEngine& mEngine;
-    std::unique_ptr<Framebuffer> mFramebuffer;
+    Framebuffer* mFramebuffer;
     status_t mStatus;
 };
 
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index b4c7c96..5956c46 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -36,6 +36,7 @@
 
     MOCK_METHOD0(createFramebuffer, std::unique_ptr<renderengine::Framebuffer>());
     MOCK_METHOD0(createImage, std::unique_ptr<renderengine::Image>());
+    MOCK_METHOD0(getFramebufferForDrawing, Framebuffer*());
     MOCK_CONST_METHOD0(primeCache, void());
     MOCK_METHOD1(dump, void(std::string&));
     MOCK_CONST_METHOD0(useNativeFenceSync, bool());
@@ -52,6 +53,7 @@
     MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
     MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
     MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
+    MOCK_METHOD4(bindExternalTextureBuffer, status_t(uint32_t, sp<GraphicBuffer>, sp<Fence>, bool));
     MOCK_CONST_METHOD0(checkErrors, void());
     MOCK_METHOD4(setViewportAndProjection,
                  void(size_t, size_t, Rect, ui::Transform::orientation_flags));
@@ -76,9 +78,9 @@
     MOCK_CONST_METHOD0(isProtected, bool());
     MOCK_CONST_METHOD0(supportsProtectedContent, bool());
     MOCK_METHOD1(useProtectedContext, bool(bool));
-    MOCK_METHOD4(drawLayers,
+    MOCK_METHOD5(drawLayers,
                  status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
-                          ANativeWindowBuffer*, base::unique_fd*));
+                          ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*));
 };
 
 } // namespace mock
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index bef25a8..f28f672 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -105,7 +105,8 @@
                            std::vector<renderengine::LayerSettings> layers,
                            sp<GraphicBuffer> buffer) {
         base::unique_fd fence;
-        status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), &fence);
+        status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(),
+                                          base::unique_fd(), &fence);
 
         int fd = fence.release();
         if (fd >= 0) {
@@ -178,6 +179,9 @@
     template <typename SourceVariant>
     void fillBufferWithRoundedCorners();
 
+    template <typename SourceVariant>
+    void overlayCorners();
+
     void fillRedBufferTextureTransform();
 
     void fillBufferTextureTransform();
@@ -194,7 +198,7 @@
 
     void clearLeftRegion();
 
-    void fillBufferThenClearRegion();
+    void clearRegion();
 
     // Dumb hack to get aroud the fact that tear-down for renderengine isn't
     // well defined right now, so we can't create multiple instances
@@ -543,6 +547,44 @@
                       255);
 }
 
+template <typename SourceVariant>
+void RenderEngineTest::overlayCorners() {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<renderengine::LayerSettings> layersFirst;
+
+    renderengine::LayerSettings layerOne;
+    layerOne.geometry.boundaries =
+            FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0);
+    SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
+    layerOne.alpha = 0.2;
+
+    layersFirst.push_back(layerOne);
+    invokeDraw(settings, layersFirst, mBuffer);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
+                           DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                      0, 0, 0, 0);
+
+    std::vector<renderengine::LayerSettings> layersSecond;
+    renderengine::LayerSettings layerTwo;
+    layerTwo.geometry.boundaries =
+            FloatRect(DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0,
+                      DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
+    SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
+    layerTwo.alpha = 1.0f;
+
+    layersSecond.push_back(layerTwo);
+    invokeDraw(settings, layersSecond, mBuffer);
+
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
+                           DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                      0, 255, 0, 255);
+}
+
 void RenderEngineTest::fillRedBufferTextureTransform() {
     renderengine::DisplaySettings settings;
     settings.physicalDisplay = fullscreenRect();
@@ -685,14 +727,13 @@
     invokeDraw(settings, layers, mBuffer);
 }
 
-void RenderEngineTest::fillBufferThenClearRegion() {
-    fillGreenBuffer<ColorSourceVariant>();
+void RenderEngineTest::clearRegion() {
     // Reuse mBuffer
     clearLeftRegion();
     expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 255);
     expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
                            DEFAULT_DISPLAY_HEIGHT),
-                      0, 255, 0, 255);
+                      0, 0, 0, 0);
 }
 
 TEST_F(RenderEngineTest, drawLayers_noLayersToDraw) {
@@ -747,6 +788,10 @@
     fillBufferWithRoundedCorners<ColorSourceVariant>();
 }
 
+TEST_F(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
+    overlayCorners<ColorSourceVariant>();
+}
+
 TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
     fillRedBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
@@ -795,6 +840,10 @@
     fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
+TEST_F(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
+    overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
 TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
     fillRedBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
@@ -843,6 +892,10 @@
     fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
+TEST_F(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
+    overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
 TEST_F(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
     fillBufferTextureTransform();
 }
@@ -855,8 +908,8 @@
     fillBufferWithoutPremultiplyAlpha();
 }
 
-TEST_F(RenderEngineTest, drawLayers_fillBufferThenClearRegion) {
-    fillBufferThenClearRegion();
+TEST_F(RenderEngineTest, drawLayers_clearRegion) {
+    clearRegion();
 }
 
 } // namespace android
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 4b20772..da91a97 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -24,12 +24,12 @@
 #include <utils/Trace.h>
 
 using ::android::base::unique_fd;
-using ::android::BufferHubDefs::AnyClientAcquired;
-using ::android::BufferHubDefs::AnyClientGained;
-using ::android::BufferHubDefs::IsClientAcquired;
-using ::android::BufferHubDefs::IsClientGained;
-using ::android::BufferHubDefs::IsClientPosted;
-using ::android::BufferHubDefs::IsClientReleased;
+using ::android::BufferHubDefs::isAnyClientAcquired;
+using ::android::BufferHubDefs::isAnyClientGained;
+using ::android::BufferHubDefs::isClientAcquired;
+using ::android::BufferHubDefs::isClientGained;
+using ::android::BufferHubDefs::isClientPosted;
+using ::android::BufferHubDefs::isClientReleased;
 using ::android::frameworks::bufferhub::V1_0::BufferHubStatus;
 using ::android::frameworks::bufferhub::V1_0::BufferTraits;
 using ::android::frameworks::bufferhub::V1_0::IBufferClient;
@@ -39,22 +39,22 @@
 
 namespace android {
 
-std::unique_ptr<BufferHubBuffer> BufferHubBuffer::Create(uint32_t width, uint32_t height,
+std::unique_ptr<BufferHubBuffer> BufferHubBuffer::create(uint32_t width, uint32_t height,
                                                          uint32_t layerCount, uint32_t format,
                                                          uint64_t usage, size_t userMetadataSize) {
     auto buffer = std::unique_ptr<BufferHubBuffer>(
             new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize));
-    return buffer->IsValid() ? std::move(buffer) : nullptr;
+    return buffer->isValid() ? std::move(buffer) : nullptr;
 }
 
-std::unique_ptr<BufferHubBuffer> BufferHubBuffer::Import(const native_handle_t* token) {
-    if (token == nullptr) {
+std::unique_ptr<BufferHubBuffer> BufferHubBuffer::import(const sp<NativeHandle>& token) {
+    if (token == nullptr || token.get() == nullptr) {
         ALOGE("%s: token cannot be nullptr!", __FUNCTION__);
         return nullptr;
     }
 
     auto buffer = std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(token));
-    return buffer->IsValid() ? std::move(buffer) : nullptr;
+    return buffer->isValid() ? std::move(buffer) : nullptr;
 }
 
 BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
@@ -78,15 +78,14 @@
     BufferHubStatus ret;
     sp<IBufferClient> client;
     BufferTraits bufferTraits;
-    IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& status, const auto& outClient,
-                                                 const auto& traits) {
+    IBufferHub::allocateBuffer_cb allocCb = [&](const auto& status, const auto& outClient,
+                                                const auto& outTraits) {
         ret = status;
         client = std::move(outClient);
-        bufferTraits = std::move(traits);
+        bufferTraits = std::move(outTraits);
     };
 
-    if (!bufferhub->allocateBuffer(desc, static_cast<uint32_t>(userMetadataSize), alloc_cb)
-                 .isOk()) {
+    if (!bufferhub->allocateBuffer(desc, static_cast<uint32_t>(userMetadataSize), allocCb).isOk()) {
         ALOGE("%s: allocateBuffer transaction failed!", __FUNCTION__);
         return;
     } else if (ret != BufferHubStatus::NO_ERROR) {
@@ -105,7 +104,7 @@
     mBufferClient = std::move(client);
 }
 
-BufferHubBuffer::BufferHubBuffer(const native_handle_t* token) {
+BufferHubBuffer::BufferHubBuffer(const sp<NativeHandle>& token) {
     sp<IBufferHub> bufferhub = IBufferHub::getService();
     if (bufferhub.get() == nullptr) {
         ALOGE("%s: BufferHub service not found!", __FUNCTION__);
@@ -115,16 +114,16 @@
     BufferHubStatus ret;
     sp<IBufferClient> client;
     BufferTraits bufferTraits;
-    IBufferHub::importBuffer_cb import_cb = [&](const auto& status, const auto& outClient,
-                                                const auto& traits) {
+    IBufferHub::importBuffer_cb importCb = [&](const auto& status, const auto& outClient,
+                                               const auto& outTraits) {
         ret = status;
         client = std::move(outClient);
-        bufferTraits = std::move(traits);
+        bufferTraits = std::move(outTraits);
     };
 
     // hidl_handle(native_handle_t*) simply creates a raw pointer reference withouth ownership
     // transfer.
-    if (!bufferhub->importBuffer(hidl_handle(token), import_cb).isOk()) {
+    if (!bufferhub->importBuffer(hidl_handle(token.get()->handle()), importCb).isOk()) {
         ALOGE("%s: importBuffer transaction failed!", __FUNCTION__);
         return;
     } else if (ret != BufferHubStatus::NO_ERROR) {
@@ -169,8 +168,8 @@
 
     // Import fds. Dup fds because hidl_handle owns the fds.
     unique_fd ashmemFd(fcntl(bufferTraits.bufferInfo->data[0], F_DUPFD_CLOEXEC, 0));
-    mMetadata = BufferHubMetadata::Import(std::move(ashmemFd));
-    if (!mMetadata.IsValid()) {
+    mMetadata = BufferHubMetadata::import(std::move(ashmemFd));
+    if (!mMetadata.isValid()) {
         ALOGE("%s: Received an invalid metadata.", __FUNCTION__);
         return -EINVAL;
     }
@@ -196,29 +195,29 @@
 
     uint32_t userMetadataSize;
     memcpy(&userMetadataSize, &bufferTraits.bufferInfo->data[4], sizeof(userMetadataSize));
-    if (mMetadata.user_metadata_size() != userMetadataSize) {
+    if (mMetadata.userMetadataSize() != userMetadataSize) {
         ALOGE("%s: user metadata size not match: expected %u, actual %zu.", __FUNCTION__,
-              userMetadataSize, mMetadata.user_metadata_size());
+              userMetadataSize, mMetadata.userMetadataSize());
         return -EINVAL;
     }
 
-    size_t metadataSize = static_cast<size_t>(mMetadata.metadata_size());
+    size_t metadataSize = static_cast<size_t>(mMetadata.metadataSize());
     if (metadataSize < BufferHubDefs::kMetadataHeaderSize) {
         ALOGE("%s: metadata too small: %zu", __FUNCTION__, metadataSize);
         return -EINVAL;
     }
 
     // Populate shortcuts to the atomics in metadata.
-    auto metadata_header = mMetadata.metadata_header();
-    buffer_state_ = &metadata_header->buffer_state;
-    fence_state_ = &metadata_header->fence_state;
-    active_clients_bit_mask_ = &metadata_header->active_clients_bit_mask;
+    auto metadataHeader = mMetadata.metadataHeader();
+    mBufferState = &metadataHeader->bufferState;
+    mFenceState = &metadataHeader->fenceState;
+    mActiveClientsBitMask = &metadataHeader->activeClientsBitMask;
     // The C++ standard recommends (but does not require) that lock-free atomic operations are
     // also address-free, that is, suitable for communication between processes using shared
     // memory.
-    LOG_ALWAYS_FATAL_IF(!std::atomic_is_lock_free(buffer_state_) ||
-                                !std::atomic_is_lock_free(fence_state_) ||
-                                !std::atomic_is_lock_free(active_clients_bit_mask_),
+    LOG_ALWAYS_FATAL_IF(!std::atomic_is_lock_free(mBufferState) ||
+                                !std::atomic_is_lock_free(mFenceState) ||
+                                !std::atomic_is_lock_free(mActiveClientsBitMask),
                         "Atomic variables in ashmen are not lock free.");
 
     // Import the buffer: We only need to hold on the native_handle_t here so that
@@ -230,105 +229,105 @@
     mClientStateMask = clientBitMask;
 
     // TODO(b/112012161) Set up shared fences.
-    ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, mId,
-          buffer_state_->load(std::memory_order_acquire));
+    ALOGD("%s: id=%d, mBufferState=%" PRIx32 ".", __FUNCTION__, mId,
+          mBufferState->load(std::memory_order_acquire));
     return 0;
 }
 
-int BufferHubBuffer::Gain() {
-    uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
-    if (IsClientGained(current_buffer_state, mClientStateMask)) {
+int BufferHubBuffer::gain() {
+    uint32_t currentBufferState = mBufferState->load(std::memory_order_acquire);
+    if (isClientGained(currentBufferState, mClientStateMask)) {
         ALOGV("%s: Buffer is already gained by this client %" PRIx32 ".", __FUNCTION__,
               mClientStateMask);
         return 0;
     }
     do {
-        if (AnyClientGained(current_buffer_state & (~mClientStateMask)) ||
-            AnyClientAcquired(current_buffer_state)) {
+        if (isAnyClientGained(currentBufferState & (~mClientStateMask)) ||
+            isAnyClientAcquired(currentBufferState)) {
             ALOGE("%s: Buffer is in use, id=%d mClientStateMask=%" PRIx32 " state=%" PRIx32 ".",
-                  __FUNCTION__, mId, mClientStateMask, current_buffer_state);
+                  __FUNCTION__, mId, mClientStateMask, currentBufferState);
             return -EBUSY;
         }
         // Change the buffer state to gained state, whose value happens to be the same as
         // mClientStateMask.
-    } while (!buffer_state_->compare_exchange_weak(current_buffer_state, mClientStateMask,
-                                                   std::memory_order_acq_rel,
-                                                   std::memory_order_acquire));
+    } while (!mBufferState->compare_exchange_weak(currentBufferState, mClientStateMask,
+                                                  std::memory_order_acq_rel,
+                                                  std::memory_order_acquire));
     // TODO(b/119837586): Update fence state and return GPU fence.
     return 0;
 }
 
-int BufferHubBuffer::Post() {
-    uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
-    uint32_t updated_buffer_state = (~mClientStateMask) & BufferHubDefs::kHighBitsMask;
+int BufferHubBuffer::post() {
+    uint32_t currentBufferState = mBufferState->load(std::memory_order_acquire);
+    uint32_t updatedBufferState = (~mClientStateMask) & BufferHubDefs::kHighBitsMask;
     do {
-        if (!IsClientGained(current_buffer_state, mClientStateMask)) {
+        if (!isClientGained(currentBufferState, mClientStateMask)) {
             ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d "
                   "mClientStateMask=%" PRIx32 " state=%" PRIx32 ".",
-                  __FUNCTION__, mId, mClientStateMask, current_buffer_state);
+                  __FUNCTION__, mId, mClientStateMask, currentBufferState);
             return -EBUSY;
         }
         // Set the producer client buffer state to released, other clients' buffer state to posted.
         // Post to all existing and non-existing clients.
-    } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
-                                                   std::memory_order_acq_rel,
-                                                   std::memory_order_acquire));
+    } while (!mBufferState->compare_exchange_weak(currentBufferState, updatedBufferState,
+                                                  std::memory_order_acq_rel,
+                                                  std::memory_order_acquire));
     // TODO(b/119837586): Update fence state and return GPU fence if needed.
     return 0;
 }
 
-int BufferHubBuffer::Acquire() {
-    uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
-    if (IsClientAcquired(current_buffer_state, mClientStateMask)) {
+int BufferHubBuffer::acquire() {
+    uint32_t currentBufferState = mBufferState->load(std::memory_order_acquire);
+    if (isClientAcquired(currentBufferState, mClientStateMask)) {
         ALOGV("%s: Buffer is already acquired by this client %" PRIx32 ".", __FUNCTION__,
               mClientStateMask);
         return 0;
     }
-    uint32_t updated_buffer_state = 0U;
+    uint32_t updatedBufferState = 0U;
     do {
-        if (!IsClientPosted(current_buffer_state, mClientStateMask)) {
+        if (!isClientPosted(currentBufferState, mClientStateMask)) {
             ALOGE("%s: Cannot acquire a buffer that is not in posted state. buffer_id=%d "
                   "mClientStateMask=%" PRIx32 " state=%" PRIx32 ".",
-                  __FUNCTION__, mId, mClientStateMask, current_buffer_state);
+                  __FUNCTION__, mId, mClientStateMask, currentBufferState);
             return -EBUSY;
         }
         // Change the buffer state for this consumer from posted to acquired.
-        updated_buffer_state = current_buffer_state ^ mClientStateMask;
-    } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
-                                                   std::memory_order_acq_rel,
-                                                   std::memory_order_acquire));
+        updatedBufferState = currentBufferState ^ mClientStateMask;
+    } while (!mBufferState->compare_exchange_weak(currentBufferState, updatedBufferState,
+                                                  std::memory_order_acq_rel,
+                                                  std::memory_order_acquire));
     // TODO(b/119837586): Update fence state and return GPU fence.
     return 0;
 }
 
-int BufferHubBuffer::Release() {
-    uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
-    if (IsClientReleased(current_buffer_state, mClientStateMask)) {
+int BufferHubBuffer::release() {
+    uint32_t currentBufferState = mBufferState->load(std::memory_order_acquire);
+    if (isClientReleased(currentBufferState, mClientStateMask)) {
         ALOGV("%s: Buffer is already released by this client %" PRIx32 ".", __FUNCTION__,
               mClientStateMask);
         return 0;
     }
-    uint32_t updated_buffer_state = 0U;
+    uint32_t updatedBufferState = 0U;
     do {
-        updated_buffer_state = current_buffer_state & (~mClientStateMask);
-    } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
-                                                   std::memory_order_acq_rel,
-                                                   std::memory_order_acquire));
+        updatedBufferState = currentBufferState & (~mClientStateMask);
+    } while (!mBufferState->compare_exchange_weak(currentBufferState, updatedBufferState,
+                                                  std::memory_order_acq_rel,
+                                                  std::memory_order_acquire));
     // TODO(b/119837586): Update fence state and return GPU fence if needed.
     return 0;
 }
 
-bool BufferHubBuffer::IsReleased() const {
-    return (buffer_state_->load(std::memory_order_acquire) &
-            active_clients_bit_mask_->load(std::memory_order_acquire)) == 0;
+bool BufferHubBuffer::isReleased() const {
+    return (mBufferState->load(std::memory_order_acquire) &
+            mActiveClientsBitMask->load(std::memory_order_acquire)) == 0;
 }
 
-bool BufferHubBuffer::IsValid() const {
+bool BufferHubBuffer::isValid() const {
     return mBufferHandle.getNativeHandle() != nullptr && mId >= 0 && mClientStateMask != 0U &&
-            mEventFd.get() >= 0 && mMetadata.IsValid() && mBufferClient != nullptr;
+            mEventFd.get() >= 0 && mMetadata.isValid() && mBufferClient != nullptr;
 }
 
-native_handle_t* BufferHubBuffer::Duplicate() {
+sp<NativeHandle> BufferHubBuffer::duplicate() {
     if (mBufferClient == nullptr) {
         ALOGE("%s: missing BufferClient!", __FUNCTION__);
         return nullptr;
@@ -336,12 +335,12 @@
 
     hidl_handle token;
     BufferHubStatus ret;
-    IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) {
+    IBufferClient::duplicate_cb dupCb = [&](const auto& outToken, const auto& status) {
         token = std::move(outToken);
         ret = status;
     };
 
-    if (!mBufferClient->duplicate(dup_cb).isOk()) {
+    if (!mBufferClient->duplicate(dupCb).isOk()) {
         ALOGE("%s: duplicate transaction failed!", __FUNCTION__);
         return nullptr;
     } else if (ret != BufferHubStatus::NO_ERROR) {
@@ -352,7 +351,7 @@
         return nullptr;
     }
 
-    return native_handle_clone(token.getNativeHandle());
+    return NativeHandle::create(native_handle_clone(token.getNativeHandle()), /*ownsHandle=*/true);
 }
 
 } // namespace android
diff --git a/libs/ui/BufferHubMetadata.cpp b/libs/ui/BufferHubMetadata.cpp
index 816707d..05bc7dd 100644
--- a/libs/ui/BufferHubMetadata.cpp
+++ b/libs/ui/BufferHubMetadata.cpp
@@ -34,7 +34,7 @@
 using BufferHubDefs::MetadataHeader;
 
 /* static */
-BufferHubMetadata BufferHubMetadata::Create(size_t userMetadataSize) {
+BufferHubMetadata BufferHubMetadata::create(size_t userMetadataSize) {
     // The size the of metadata buffer is used as the "width" parameter during allocation. Thus it
     // cannot overflow uint32_t.
     if (userMetadataSize >= (std::numeric_limits<uint32_t>::max() - kMetadataHeaderSize)) {
@@ -59,11 +59,11 @@
         return {};
     }
 
-    return BufferHubMetadata::Import(std::move(ashmemFd));
+    return BufferHubMetadata::import(std::move(ashmemFd));
 }
 
 /* static */
-BufferHubMetadata BufferHubMetadata::Import(unique_fd ashmemFd) {
+BufferHubMetadata BufferHubMetadata::import(unique_fd ashmemFd) {
     if (!ashmem_valid(ashmemFd.get())) {
         ALOGE("BufferHubMetadata::Import: invalid ashmem fd.");
         return {};
@@ -94,7 +94,7 @@
 
 BufferHubMetadata::~BufferHubMetadata() {
     if (mMetadataHeader != nullptr) {
-        int ret = munmap(mMetadataHeader, metadata_size());
+        int ret = munmap(mMetadataHeader, metadataSize());
         ALOGE_IF(ret != 0,
                  "BufferHubMetadata::~BufferHubMetadata: failed to unmap ashmem, error=%d.", errno);
         mMetadataHeader = nullptr;
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index e678c58..79958ec 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "GraphicBuffer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <ui/GraphicBuffer.h>
 
@@ -29,6 +30,7 @@
 #include <ui/Gralloc2.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
+#include <utils/Trace.h>
 
 namespace android {
 
@@ -100,7 +102,7 @@
         return;
     }
 
-    mInitCheck = initWithHandle(buffer->DuplicateHandle(), /*method=*/TAKE_UNREGISTERED_HANDLE,
+    mInitCheck = initWithHandle(buffer->duplicateHandle(), /*method=*/TAKE_UNREGISTERED_HANDLE,
                                 buffer->desc().width, buffer->desc().height,
                                 static_cast<PixelFormat>(buffer->desc().format),
                                 buffer->desc().layers, buffer->desc().usage, buffer->desc().stride);
@@ -111,6 +113,7 @@
 
 GraphicBuffer::~GraphicBuffer()
 {
+    ATRACE_CALL();
     if (handle) {
         free_handle();
     }
@@ -286,22 +289,22 @@
     return res;
 }
 
-status_t GraphicBuffer::lockAsync(uint32_t inUsage, void** vaddr, int fenceFd)
-{
+status_t GraphicBuffer::lockAsync(uint32_t inUsage, void** vaddr, int fenceFd,
+                                  int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
     const Rect lockBounds(width, height);
-    status_t res = lockAsync(inUsage, lockBounds, vaddr, fenceFd);
+    status_t res =
+            lockAsync(inUsage, lockBounds, vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
     return res;
 }
 
-status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect,
-        void** vaddr, int fenceFd)
-{
-    return lockAsync(inUsage, inUsage, rect, vaddr, fenceFd);
+status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd,
+                                  int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
+    return lockAsync(inUsage, inUsage, rect, vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
 }
 
-status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage,
-        uint64_t inConsumerUsage, const Rect& rect, void** vaddr, int fenceFd)
-{
+status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage,
+                                  const Rect& rect, void** vaddr, int fenceFd,
+                                  int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
     if (rect.left < 0 || rect.right  > width ||
         rect.top  < 0 || rect.bottom > height) {
         ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
@@ -310,9 +313,9 @@
         return BAD_VALUE;
     }
 
-    int32_t bytesPerPixel, bytesPerStride;
     status_t res = getBufferMapper().lockAsync(handle, inProducerUsage, inConsumerUsage, rect,
-                                               vaddr, fenceFd, &bytesPerPixel, &bytesPerStride);
+                                               vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
+
     return res;
 }
 
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index 0b6d75a..5ba189c 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -23,20 +23,19 @@
 #include <ui/BufferHubDefs.h>
 #include <ui/BufferHubEventFd.h>
 #include <ui/BufferHubMetadata.h>
+#include <utils/NativeHandle.h>
 
 namespace android {
 
 class BufferHubBuffer {
 public:
     // Allocates a standalone BufferHubBuffer.
-    static std::unique_ptr<BufferHubBuffer> Create(uint32_t width, uint32_t height,
+    static std::unique_ptr<BufferHubBuffer> create(uint32_t width, uint32_t height,
                                                    uint32_t layerCount, uint32_t format,
                                                    uint64_t usage, size_t userMetadataSize);
 
-    // Imports the given token to a BufferHubBuffer. Not taking ownership of the token. Caller
-    // should close and destroy the token after calling this function regardless of output.
-    // TODO(b/122543147): use a movable wrapper for token
-    static std::unique_ptr<BufferHubBuffer> Import(const native_handle_t* token);
+    // Imports the given token to a BufferHubBuffer. Not taking ownership of the token.
+    static std::unique_ptr<BufferHubBuffer> import(const sp<NativeHandle>& token);
 
     BufferHubBuffer(const BufferHubBuffer&) = delete;
     void operator=(const BufferHubBuffer&) = delete;
@@ -52,65 +51,63 @@
 
     // Duplicate the underlying Gralloc buffer handle. Caller is responsible to free the handle
     // after use.
-    native_handle_t* DuplicateHandle() {
+    native_handle_t* duplicateHandle() {
         return native_handle_clone(mBufferHandle.getNativeHandle());
     }
 
     const BufferHubEventFd& eventFd() const { return mEventFd; }
 
-    // Returns the current value of MetadataHeader::buffer_state.
-    uint32_t buffer_state() const { return buffer_state_->load(std::memory_order_acquire); }
+    // Returns the current value of MetadataHeader::bufferState.
+    uint32_t bufferState() const { return mBufferState->load(std::memory_order_acquire); }
 
     // A state mask which is unique to a buffer hub client among all its siblings sharing the same
     // concrete graphic buffer.
-    uint32_t client_state_mask() const { return mClientStateMask; }
+    uint32_t clientStateMask() const { return mClientStateMask; }
 
-    size_t user_metadata_size() const { return mMetadata.user_metadata_size(); }
+    size_t userMetadataSize() const { return mMetadata.userMetadataSize(); }
 
     // Returns true if the BufferClient is still alive.
-    bool IsConnected() const { return mBufferClient->ping().isOk(); }
+    bool isConnected() const { return mBufferClient->ping().isOk(); }
 
     // Returns true if the buffer is valid: non-null buffer handle, valid id, valid client bit mask,
     // valid metadata and valid buffer client
-    bool IsValid() const;
+    bool isValid() const;
 
     // Gains the buffer for exclusive write permission. Read permission is implied once a buffer is
     // gained.
     // The buffer can be gained as long as there is no other client in acquired or gained state.
-    int Gain();
+    int gain();
 
     // Posts the gained buffer for other buffer clients to use the buffer.
     // The buffer can be posted iff the buffer state for this client is gained.
     // After posting the buffer, this client is put to released state and does not have access to
     // the buffer for this cycle of the usage of the buffer.
-    int Post();
+    int post();
 
     // Acquires the buffer for shared read permission.
     // The buffer can be acquired iff the buffer state for this client is posted.
-    int Acquire();
+    int acquire();
 
     // Releases the buffer.
     // The buffer can be released from any buffer state.
     // After releasing the buffer, this client no longer have any permissions to the buffer for the
     // current cycle of the usage of the buffer.
-    int Release();
+    int release();
 
     // Returns whether the buffer is released by all active clients or not.
-    bool IsReleased() const;
+    bool isReleased() const;
 
     // Creates a token that stands for this BufferHubBuffer client and could be used for Import to
     // create another BufferHubBuffer. The new BufferHubBuffer will share the same underlying
-    // gralloc buffer and ashmem region for metadata. Note that the caller owns the token and
-    // should free it after use.
+    // gralloc buffer and ashmem region for metadata. Not taking ownership of the token.
     // Returns a valid token on success, nullptr on failure.
-    // TODO(b/122543147): use a movable wrapper for token
-    native_handle_t* Duplicate();
+    sp<NativeHandle> duplicate();
 
 private:
     BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format,
                     uint64_t usage, size_t userMetadataSize);
 
-    BufferHubBuffer(const native_handle_t* token);
+    BufferHubBuffer(const sp<NativeHandle>& token);
 
     int initWithBufferTraits(const frameworks::bufferhub::V1_0::BufferTraits& bufferTraits);
 
@@ -134,9 +131,9 @@
     // bufferhubd daemon and all buffer clients.
     BufferHubMetadata mMetadata;
     // Shortcuts to the atomics inside the header of mMetadata.
-    std::atomic<uint32_t>* buffer_state_ = nullptr;
-    std::atomic<uint32_t>* fence_state_ = nullptr;
-    std::atomic<uint32_t>* active_clients_bit_mask_ = nullptr;
+    std::atomic<uint32_t>* mBufferState = nullptr;
+    std::atomic<uint32_t>* mFenceState = nullptr;
+    std::atomic<uint32_t>* mActiveClientsBitMask = nullptr;
 
     // HwBinder backend
     sp<frameworks::bufferhub::V1_0::IBufferClient> mBufferClient;
diff --git a/libs/ui/include/ui/BufferHubDefs.h b/libs/ui/include/ui/BufferHubDefs.h
index ff970cb..10f274f 100644
--- a/libs/ui/include/ui/BufferHubDefs.h
+++ b/libs/ui/include/ui/BufferHubDefs.h
@@ -32,7 +32,7 @@
 // Single buffer clients (up to 16) ownership signal.
 // 32-bit atomic unsigned int.
 // Each client takes 2 bits. The first bit locates in the first 16 bits of
-// buffer_state; the second bit locates in the last 16 bits of buffer_state.
+// bufferState; the second bit locates in the last 16 bits of bufferState.
 // Client states:
 // Gained state 11. Exclusive write state.
 // Posted state 10.
@@ -63,63 +63,63 @@
 static constexpr uint32_t kFirstClientBitMask = (1U << kMaxNumberOfClients) + 1U;
 
 // Returns true if any of the client is in gained state.
-static inline bool AnyClientGained(uint32_t state) {
-    uint32_t high_bits = state >> kMaxNumberOfClients;
-    uint32_t low_bits = state & kLowbitsMask;
-    return high_bits == low_bits && low_bits != 0U;
+static inline bool isAnyClientGained(uint32_t state) {
+    uint32_t highBits = state >> kMaxNumberOfClients;
+    uint32_t lowBits = state & kLowbitsMask;
+    return highBits == lowBits && lowBits != 0U;
 }
 
 // Returns true if the input client is in gained state.
-static inline bool IsClientGained(uint32_t state, uint32_t client_bit_mask) {
+static inline bool isClientGained(uint32_t state, uint32_t client_bit_mask) {
     return state == client_bit_mask;
 }
 
 // Returns true if any of the client is in posted state.
-static inline bool AnyClientPosted(uint32_t state) {
-    uint32_t high_bits = state >> kMaxNumberOfClients;
-    uint32_t low_bits = state & kLowbitsMask;
-    uint32_t posted_or_acquired = high_bits ^ low_bits;
-    return posted_or_acquired & high_bits;
+static inline bool isAnyClientPosted(uint32_t state) {
+    uint32_t highBits = state >> kMaxNumberOfClients;
+    uint32_t lowBits = state & kLowbitsMask;
+    uint32_t postedOrAcquired = highBits ^ lowBits;
+    return postedOrAcquired & highBits;
 }
 
 // Returns true if the input client is in posted state.
-static inline bool IsClientPosted(uint32_t state, uint32_t client_bit_mask) {
-    uint32_t client_bits = state & client_bit_mask;
-    if (client_bits == 0U) return false;
-    uint32_t low_bits = client_bits & kLowbitsMask;
-    return low_bits == 0U;
+static inline bool isClientPosted(uint32_t state, uint32_t client_bit_mask) {
+    uint32_t clientBits = state & client_bit_mask;
+    if (clientBits == 0U) return false;
+    uint32_t lowBits = clientBits & kLowbitsMask;
+    return lowBits == 0U;
 }
 
 // Return true if any of the client is in acquired state.
-static inline bool AnyClientAcquired(uint32_t state) {
-    uint32_t high_bits = state >> kMaxNumberOfClients;
-    uint32_t low_bits = state & kLowbitsMask;
-    uint32_t posted_or_acquired = high_bits ^ low_bits;
-    return posted_or_acquired & low_bits;
+static inline bool isAnyClientAcquired(uint32_t state) {
+    uint32_t highBits = state >> kMaxNumberOfClients;
+    uint32_t lowBits = state & kLowbitsMask;
+    uint32_t postedOrAcquired = highBits ^ lowBits;
+    return postedOrAcquired & lowBits;
 }
 
 // Return true if the input client is in acquired state.
-static inline bool IsClientAcquired(uint32_t state, uint32_t client_bit_mask) {
-    uint32_t client_bits = state & client_bit_mask;
-    if (client_bits == 0U) return false;
-    uint32_t high_bits = client_bits & kHighBitsMask;
-    return high_bits == 0U;
+static inline bool isClientAcquired(uint32_t state, uint32_t client_bit_mask) {
+    uint32_t clientBits = state & client_bit_mask;
+    if (clientBits == 0U) return false;
+    uint32_t highBits = clientBits & kHighBitsMask;
+    return highBits == 0U;
 }
 
 // Returns true if the input client is in released state.
-static inline bool IsClientReleased(uint32_t state, uint32_t client_bit_mask) {
+static inline bool isClientReleased(uint32_t state, uint32_t client_bit_mask) {
     return (state & client_bit_mask) == 0U;
 }
 
 // Returns the next available buffer client's client_state_masks.
 // @params union_bits. Union of all existing clients' client_state_masks.
-static inline uint32_t FindNextAvailableClientStateMask(uint32_t union_bits) {
-    uint32_t low_union = union_bits & kLowbitsMask;
-    if (low_union == kLowbitsMask) return 0U;
-    uint32_t incremented = low_union + 1U;
-    uint32_t difference = incremented ^ low_union;
-    uint32_t new_low_bit = (difference + 1U) >> 1;
-    return new_low_bit + (new_low_bit << kMaxNumberOfClients);
+static inline uint32_t findNextAvailableClientStateMask(uint32_t union_bits) {
+    uint32_t lowUnion = union_bits & kLowbitsMask;
+    if (lowUnion == kLowbitsMask) return 0U;
+    uint32_t incremented = lowUnion + 1U;
+    uint32_t difference = incremented ^ lowUnion;
+    uint32_t newLowBit = (difference + 1U) >> 1;
+    return newLowBit + (newLowBit << kMaxNumberOfClients);
 }
 
 struct __attribute__((aligned(8))) MetadataHeader {
@@ -129,22 +129,22 @@
     // platform (include Apps and vendor HAL).
 
     // Every client takes up one bit from the higher 32 bits and one bit from the lower 32 bits in
-    // buffer_state.
-    std::atomic<uint32_t> buffer_state;
+    // bufferState.
+    std::atomic<uint32_t> bufferState;
 
-    // Every client takes up one bit in fence_state. Only the lower 32 bits are valid. The upper 32
+    // Every client takes up one bit in fenceState. Only the lower 32 bits are valid. The upper 32
     // bits are there for easier manipulation, but the value should be ignored.
-    std::atomic<uint32_t> fence_state;
+    std::atomic<uint32_t> fenceState;
 
     // Every client takes up one bit from the higher 32 bits and one bit from the lower 32 bits in
-    // active_clients_bit_mask.
-    std::atomic<uint32_t> active_clients_bit_mask;
+    // activeClientsBitMask.
+    std::atomic<uint32_t> activeClientsBitMask;
 
     // Explicit padding 4 bytes.
     uint32_t padding;
 
     // The index of the buffer queue where the buffer belongs to.
-    uint64_t queue_index;
+    uint64_t queueIndex;
 
     // Public data format, which should be updated with caution. See more details in dvr_api.h
     DvrNativeBufferMetadata metadata;
diff --git a/libs/ui/include/ui/BufferHubMetadata.h b/libs/ui/include/ui/BufferHubMetadata.h
index 2121894..3482507 100644
--- a/libs/ui/include/ui/BufferHubMetadata.h
+++ b/libs/ui/include/ui/BufferHubMetadata.h
@@ -33,12 +33,12 @@
     // @param userMetadataSize Size in bytes of the user defined metadata. The entire metadata
     //        shared memory region to be allocated is the size of canonical
     //        BufferHubDefs::MetadataHeader plus userMetadataSize.
-    static BufferHubMetadata Create(size_t userMetadataSize);
+    static BufferHubMetadata create(size_t userMetadataSize);
 
     // Imports an existing BufferHubMetadata from an ashmem FD.
     //
     // @param ashmemFd Ashmem file descriptor representing an ashmem region.
-    static BufferHubMetadata Import(unique_fd ashmemFd);
+    static BufferHubMetadata import(unique_fd ashmemFd);
 
     BufferHubMetadata() = default;
 
@@ -63,13 +63,13 @@
 
     // Returns true if the metadata is valid, i.e. the metadata has a valid ashmem fd and the ashmem
     // has been mapped into virtual address space.
-    bool IsValid() const { return mAshmemFd.get() != -1 && mMetadataHeader != nullptr; }
+    bool isValid() const { return mAshmemFd.get() != -1 && mMetadataHeader != nullptr; }
 
-    size_t user_metadata_size() const { return mUserMetadataSize; }
-    size_t metadata_size() const { return mUserMetadataSize + BufferHubDefs::kMetadataHeaderSize; }
+    size_t userMetadataSize() const { return mUserMetadataSize; }
+    size_t metadataSize() const { return mUserMetadataSize + BufferHubDefs::kMetadataHeaderSize; }
 
-    const unique_fd& ashmem_fd() const { return mAshmemFd; }
-    BufferHubDefs::MetadataHeader* metadata_header() { return mMetadataHeader; }
+    const unique_fd& ashmemFd() const { return mAshmemFd; }
+    BufferHubDefs::MetadataHeader* metadataHeader() { return mMetadataHeader; }
 
 private:
     BufferHubMetadata(size_t userMetadataSize, unique_fd ashmemFd,
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 7d88c58..4d4ee68 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -180,11 +180,15 @@
     status_t lockYCbCr(uint32_t inUsage, const Rect& rect,
             android_ycbcr *ycbcr);
     status_t unlock();
-    status_t lockAsync(uint32_t inUsage, void** vaddr, int fenceFd);
-    status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr,
-            int fenceFd);
-    status_t lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage,
-            const Rect& rect, void** vaddr, int fenceFd);
+    // For the following three lockAsync functions, if bytesPerStride or bytesPerPixel
+    // are unknown or variable, -1 will be returned
+    status_t lockAsync(uint32_t inUsage, void** vaddr, int fenceFd,
+                       int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
+    status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd,
+                       int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
+    status_t lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage, const Rect& rect,
+                       void** vaddr, int fenceFd, int32_t* outBytesPerPixel = nullptr,
+                       int32_t* outBytesPerStride = nullptr);
     status_t lockAsyncYCbCr(uint32_t inUsage, android_ycbcr *ycbcr,
             int fenceFd);
     status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect,
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
index 4b03e44..5dc56c8 100644
--- a/libs/ui/include/ui/GraphicTypes.h
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -16,13 +16,21 @@
 
 #pragma once
 
+#include <cinttypes>
+#include <cstdint>
+
 #include <android/hardware/graphics/common/1.1/types.h>
 #include <android/hardware/graphics/common/1.2/types.h>
 #include <system/graphics.h>
 
+#define ANDROID_PHYSICAL_DISPLAY_ID_FORMAT PRIu64
+
+namespace android {
+
+using PhysicalDisplayId = uint64_t;
+
 // android::ui::* in this header file will alias different types as
 // the HIDL interface is updated.
-namespace android {
 namespace ui {
 
 using android::hardware::graphics::common::V1_1::RenderIntent;
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index 3bcd935..efc1a80 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -32,13 +32,13 @@
 
 namespace {
 
-using ::android::BufferHubDefs::AnyClientAcquired;
-using ::android::BufferHubDefs::AnyClientGained;
-using ::android::BufferHubDefs::AnyClientPosted;
-using ::android::BufferHubDefs::IsClientAcquired;
-using ::android::BufferHubDefs::IsClientGained;
-using ::android::BufferHubDefs::IsClientPosted;
-using ::android::BufferHubDefs::IsClientReleased;
+using ::android::BufferHubDefs::isAnyClientAcquired;
+using ::android::BufferHubDefs::isAnyClientGained;
+using ::android::BufferHubDefs::isAnyClientPosted;
+using ::android::BufferHubDefs::isClientAcquired;
+using ::android::BufferHubDefs::isClientGained;
+using ::android::BufferHubDefs::isClientPosted;
+using ::android::BufferHubDefs::isClientReleased;
 using ::android::BufferHubDefs::kMetadataHeaderSize;
 using ::testing::IsNull;
 using ::testing::NotNull;
@@ -81,88 +81,83 @@
 };
 
 void BufferHubBufferStateTransitionTest::CreateTwoClientsOfABuffer() {
-    b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+    b1 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
     ASSERT_THAT(b1, NotNull());
-    b1ClientMask = b1->client_state_mask();
+    b1ClientMask = b1->clientStateMask();
     ASSERT_NE(b1ClientMask, 0U);
 
-    native_handle_t* token = b1->Duplicate();
+    sp<NativeHandle> token = b1->duplicate();
     ASSERT_THAT(token, NotNull());
 
-    // TODO(b/122543147): use a movalbe wrapper for token
-    b2 = BufferHubBuffer::Import(token);
-    native_handle_close(token);
-    native_handle_delete(token);
+    b2 = BufferHubBuffer::import(token);
     ASSERT_THAT(b2, NotNull());
 
-    b2ClientMask = b2->client_state_mask();
+    b2ClientMask = b2->clientStateMask();
     ASSERT_NE(b2ClientMask, 0U);
     ASSERT_NE(b2ClientMask, b1ClientMask);
 }
 
 TEST_F(BufferHubBufferTest, CreateBufferFails) {
     // Buffer Creation will fail: BLOB format requires height to be 1.
-    auto b1 = BufferHubBuffer::Create(kWidth, /*height=*/2, kLayerCount,
+    auto b1 = BufferHubBuffer::create(kWidth, /*height=*/2, kLayerCount,
                                       /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage, kUserMetadataSize);
 
     EXPECT_THAT(b1, IsNull());
 
     // Buffer Creation will fail: user metadata size too large.
-    auto b2 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+    auto b2 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       /*userMetadataSize=*/std::numeric_limits<size_t>::max());
 
     EXPECT_THAT(b2, IsNull());
 
     // Buffer Creation will fail: user metadata size too large.
     const size_t userMetadataSize = std::numeric_limits<size_t>::max() - kMetadataHeaderSize;
-    auto b3 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+    auto b3 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       userMetadataSize);
 
     EXPECT_THAT(b3, IsNull());
 }
 
 TEST_F(BufferHubBufferTest, CreateBuffer) {
-    auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+    auto b1 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       kUserMetadataSize);
     ASSERT_THAT(b1, NotNull());
-    EXPECT_TRUE(b1->IsConnected());
-    EXPECT_TRUE(b1->IsValid());
+    EXPECT_TRUE(b1->isConnected());
+    EXPECT_TRUE(b1->isValid());
     EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), kDesc));
-    EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
+    EXPECT_EQ(b1->userMetadataSize(), kUserMetadataSize);
 }
 
 TEST_F(BufferHubBufferTest, DuplicateAndImportBuffer) {
-    auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+    auto b1 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       kUserMetadataSize);
     ASSERT_THAT(b1, NotNull());
-    EXPECT_TRUE(b1->IsValid());
+    EXPECT_TRUE(b1->isValid());
 
-    native_handle_t* token = b1->Duplicate();
-    EXPECT_TRUE(token);
+    sp<NativeHandle> token = b1->duplicate();
+    ASSERT_THAT(token, NotNull());
 
     // The detached buffer should still be valid.
-    EXPECT_TRUE(b1->IsConnected());
-    EXPECT_TRUE(b1->IsValid());
+    EXPECT_TRUE(b1->isConnected());
+    EXPECT_TRUE(b1->isValid());
 
-    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
-    native_handle_close(token);
-    native_handle_delete(token);
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::import(token);
 
     ASSERT_THAT(b2, NotNull());
-    EXPECT_TRUE(b2->IsValid());
+    EXPECT_TRUE(b2->isValid());
 
     EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), b2->desc()));
-    EXPECT_EQ(b1->user_metadata_size(), b2->user_metadata_size());
+    EXPECT_EQ(b1->userMetadataSize(), b2->userMetadataSize());
 
     // These two buffer instances are based on the same physical buffer under the
     // hood, so they should share the same id.
     EXPECT_EQ(b1->id(), b2->id());
-    // We use client_state_mask() to tell those two instances apart.
-    EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
+    // We use clientStateMask() to tell those two instances apart.
+    EXPECT_NE(b1->clientStateMask(), b2->clientStateMask());
 
     // Both buffer instances should be in released state currently.
-    EXPECT_TRUE(b1->IsReleased());
-    EXPECT_TRUE(b2->IsReleased());
+    EXPECT_TRUE(b1->isReleased());
+    EXPECT_TRUE(b2->isReleased());
 
     // The event fd should behave like duped event fds.
     const BufferHubEventFd& eventFd1 = b1->eventFd();
@@ -192,21 +187,18 @@
 }
 
 TEST_F(BufferHubBufferTest, ImportFreedBuffer) {
-    auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+    auto b1 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       kUserMetadataSize);
     ASSERT_THAT(b1, NotNull());
-    EXPECT_TRUE(b1->IsValid());
+    EXPECT_TRUE(b1->isValid());
 
-    native_handle_t* token = b1->Duplicate();
-    EXPECT_TRUE(token);
+    sp<NativeHandle> token = b1->duplicate();
+    ASSERT_THAT(token, NotNull());
 
     // Explicitly destroy b1. Backend buffer should be freed and token becomes invalid
     b1.reset();
 
-    // TODO(b/122543147): use a movalbe wrapper for token
-    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
-    native_handle_close(token);
-    native_handle_delete(token);
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::import(token);
 
     // Import should fail with INVALID_TOKEN
     EXPECT_THAT(b2, IsNull());
@@ -214,7 +206,7 @@
 
 // nullptr must not crash the service
 TEST_F(BufferHubBufferTest, ImportNullToken) {
-    auto b1 = BufferHubBuffer::Import(nullptr);
+    auto b1 = BufferHubBuffer::import(nullptr);
     EXPECT_THAT(b1, IsNull());
 }
 
@@ -222,185 +214,185 @@
     native_handle_t* token = native_handle_create(/*numFds=*/0, /*numInts=*/1);
     token->data[0] = 0;
 
-    auto b1 = BufferHubBuffer::Import(token);
-    native_handle_delete(token);
+    sp<NativeHandle> tokenHandle = NativeHandle::create(token, /*ownHandle=*/true);
+    auto b1 = BufferHubBuffer::import(tokenHandle);
 
     EXPECT_THAT(b1, IsNull());
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromReleasedState) {
-    ASSERT_TRUE(b1->IsReleased());
+    ASSERT_TRUE(b1->isReleased());
 
     // Successful gaining the buffer should change the buffer state bit of b1 to
     // gained state, other client state bits to released state.
-    EXPECT_EQ(b1->Gain(), 0);
-    EXPECT_TRUE(IsClientGained(b1->buffer_state(), b1ClientMask));
+    EXPECT_EQ(b1->gain(), 0);
+    EXPECT_TRUE(isClientGained(b1->bufferState(), b1ClientMask));
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromGainedState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    auto current_buffer_state = b1->buffer_state();
-    ASSERT_TRUE(IsClientGained(current_buffer_state, b1ClientMask));
+    ASSERT_EQ(b1->gain(), 0);
+    auto currentBufferState = b1->bufferState();
+    ASSERT_TRUE(isClientGained(currentBufferState, b1ClientMask));
 
     // Gaining from gained state by the same client should not return error.
-    EXPECT_EQ(b1->Gain(), 0);
+    EXPECT_EQ(b1->gain(), 0);
 
     // Gaining from gained state by another client should return error.
-    EXPECT_EQ(b2->Gain(), -EBUSY);
+    EXPECT_EQ(b2->gain(), -EBUSY);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromAcquiredState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_EQ(b1->Post(), 0);
-    ASSERT_EQ(b2->Acquire(), 0);
-    ASSERT_TRUE(AnyClientAcquired(b1->buffer_state()));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_EQ(b2->acquire(), 0);
+    ASSERT_TRUE(isAnyClientAcquired(b1->bufferState()));
 
     // Gaining from acquired state should fail.
-    EXPECT_EQ(b1->Gain(), -EBUSY);
-    EXPECT_EQ(b2->Gain(), -EBUSY);
+    EXPECT_EQ(b1->gain(), -EBUSY);
+    EXPECT_EQ(b2->gain(), -EBUSY);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromOtherClientInPostedState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_EQ(b1->Post(), 0);
-    ASSERT_TRUE(AnyClientPosted(b1->buffer_state()));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_TRUE(isAnyClientPosted(b1->bufferState()));
 
     // Gaining a buffer who has other posted client should succeed.
-    EXPECT_EQ(b1->Gain(), 0);
+    EXPECT_EQ(b1->gain(), 0);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromSelfInPostedState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_EQ(b1->Post(), 0);
-    ASSERT_TRUE(AnyClientPosted(b1->buffer_state()));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_TRUE(isAnyClientPosted(b1->bufferState()));
 
     // A posted client should be able to gain the buffer when there is no other clients in
     // acquired state.
-    EXPECT_EQ(b2->Gain(), 0);
+    EXPECT_EQ(b2->gain(), 0);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromOtherInGainedState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_TRUE(IsClientGained(b1->buffer_state(), b1ClientMask));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_TRUE(isClientGained(b1->bufferState(), b1ClientMask));
 
-    EXPECT_EQ(b2->Post(), -EBUSY);
+    EXPECT_EQ(b2->post(), -EBUSY);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromSelfInGainedState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_TRUE(IsClientGained(b1->buffer_state(), b1ClientMask));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_TRUE(isClientGained(b1->bufferState(), b1ClientMask));
 
-    EXPECT_EQ(b1->Post(), 0);
-    auto current_buffer_state = b1->buffer_state();
-    EXPECT_TRUE(IsClientReleased(current_buffer_state, b1ClientMask));
-    EXPECT_TRUE(IsClientPosted(current_buffer_state, b2ClientMask));
+    EXPECT_EQ(b1->post(), 0);
+    auto currentBufferState = b1->bufferState();
+    EXPECT_TRUE(isClientReleased(currentBufferState, b1ClientMask));
+    EXPECT_TRUE(isClientPosted(currentBufferState, b2ClientMask));
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromPostedState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_EQ(b1->Post(), 0);
-    ASSERT_TRUE(AnyClientPosted(b1->buffer_state()));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_TRUE(isAnyClientPosted(b1->bufferState()));
 
     // Post from posted state should fail.
-    EXPECT_EQ(b1->Post(), -EBUSY);
-    EXPECT_EQ(b2->Post(), -EBUSY);
+    EXPECT_EQ(b1->post(), -EBUSY);
+    EXPECT_EQ(b2->post(), -EBUSY);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromAcquiredState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_EQ(b1->Post(), 0);
-    ASSERT_EQ(b2->Acquire(), 0);
-    ASSERT_TRUE(AnyClientAcquired(b1->buffer_state()));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_EQ(b2->acquire(), 0);
+    ASSERT_TRUE(isAnyClientAcquired(b1->bufferState()));
 
     // Posting from acquired state should fail.
-    EXPECT_EQ(b1->Post(), -EBUSY);
-    EXPECT_EQ(b2->Post(), -EBUSY);
+    EXPECT_EQ(b1->post(), -EBUSY);
+    EXPECT_EQ(b2->post(), -EBUSY);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromReleasedState) {
-    ASSERT_TRUE(b1->IsReleased());
+    ASSERT_TRUE(b1->isReleased());
 
     // Posting from released state should fail.
-    EXPECT_EQ(b1->Post(), -EBUSY);
-    EXPECT_EQ(b2->Post(), -EBUSY);
+    EXPECT_EQ(b1->post(), -EBUSY);
+    EXPECT_EQ(b2->post(), -EBUSY);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromSelfInPostedState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_EQ(b1->Post(), 0);
-    ASSERT_TRUE(IsClientPosted(b1->buffer_state(), b2ClientMask));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_TRUE(isClientPosted(b1->bufferState(), b2ClientMask));
 
     // Acquire from posted state should pass.
-    EXPECT_EQ(b2->Acquire(), 0);
+    EXPECT_EQ(b2->acquire(), 0);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromOtherInPostedState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_EQ(b1->Post(), 0);
-    ASSERT_TRUE(IsClientPosted(b1->buffer_state(), b2ClientMask));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_TRUE(isClientPosted(b1->bufferState(), b2ClientMask));
 
     // Acquire from released state should fail, although there are other clients
     // in posted state.
-    EXPECT_EQ(b1->Acquire(), -EBUSY);
+    EXPECT_EQ(b1->acquire(), -EBUSY);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromSelfInAcquiredState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_EQ(b1->Post(), 0);
-    ASSERT_EQ(b2->Acquire(), 0);
-    auto current_buffer_state = b1->buffer_state();
-    ASSERT_TRUE(IsClientAcquired(current_buffer_state, b2ClientMask));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_EQ(b2->acquire(), 0);
+    auto currentBufferState = b1->bufferState();
+    ASSERT_TRUE(isClientAcquired(currentBufferState, b2ClientMask));
 
     // Acquiring from acquired state by the same client should not error out.
-    EXPECT_EQ(b2->Acquire(), 0);
+    EXPECT_EQ(b2->acquire(), 0);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromReleasedState) {
-    ASSERT_TRUE(b1->IsReleased());
+    ASSERT_TRUE(b1->isReleased());
 
     // Acquiring form released state should fail.
-    EXPECT_EQ(b1->Acquire(), -EBUSY);
-    EXPECT_EQ(b2->Acquire(), -EBUSY);
+    EXPECT_EQ(b1->acquire(), -EBUSY);
+    EXPECT_EQ(b2->acquire(), -EBUSY);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromGainedState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_TRUE(AnyClientGained(b1->buffer_state()));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_TRUE(isAnyClientGained(b1->bufferState()));
 
     // Acquiring from gained state should fail.
-    EXPECT_EQ(b1->Acquire(), -EBUSY);
-    EXPECT_EQ(b2->Acquire(), -EBUSY);
+    EXPECT_EQ(b1->acquire(), -EBUSY);
+    EXPECT_EQ(b2->acquire(), -EBUSY);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInReleasedState) {
-    ASSERT_TRUE(b1->IsReleased());
+    ASSERT_TRUE(b1->isReleased());
 
-    EXPECT_EQ(b1->Release(), 0);
+    EXPECT_EQ(b1->release(), 0);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInGainedState) {
-    ASSERT_TRUE(b1->IsReleased());
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_TRUE(AnyClientGained(b1->buffer_state()));
+    ASSERT_TRUE(b1->isReleased());
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_TRUE(isAnyClientGained(b1->bufferState()));
 
-    EXPECT_EQ(b1->Release(), 0);
+    EXPECT_EQ(b1->release(), 0);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInPostedState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_EQ(b1->Post(), 0);
-    ASSERT_TRUE(AnyClientPosted(b1->buffer_state()));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_TRUE(isAnyClientPosted(b1->bufferState()));
 
-    EXPECT_EQ(b2->Release(), 0);
+    EXPECT_EQ(b2->release(), 0);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInAcquiredState) {
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_EQ(b1->Post(), 0);
-    ASSERT_EQ(b2->Acquire(), 0);
-    ASSERT_TRUE(AnyClientAcquired(b1->buffer_state()));
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_EQ(b2->acquire(), 0);
+    ASSERT_TRUE(isAnyClientAcquired(b1->bufferState()));
 
-    EXPECT_EQ(b2->Release(), 0);
+    EXPECT_EQ(b2->release(), 0);
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, BasicUsage) {
@@ -408,60 +400,54 @@
     // Test if this set of basic operation succeed:
     // Producer post three times to the consumer, and released by consumer.
     for (int i = 0; i < 3; ++i) {
-        ASSERT_EQ(b1->Gain(), 0);
-        ASSERT_EQ(b1->Post(), 0);
-        ASSERT_EQ(b2->Acquire(), 0);
-        ASSERT_EQ(b2->Release(), 0);
+        ASSERT_EQ(b1->gain(), 0);
+        ASSERT_EQ(b1->post(), 0);
+        ASSERT_EQ(b2->acquire(), 0);
+        ASSERT_EQ(b2->release(), 0);
     }
 }
 
 TEST_F(BufferHubBufferTest, createNewConsumerAfterGain) {
     // Create a poducer buffer and gain.
     std::unique_ptr<BufferHubBuffer> b1 =
-            BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+            BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                     kUserMetadataSize);
     ASSERT_THAT(b1, NotNull());
-    ASSERT_EQ(b1->Gain(), 0);
+    ASSERT_EQ(b1->gain(), 0);
 
     // Create a consumer of the buffer and test if the consumer can acquire the
     // buffer if producer posts.
-    // TODO(b/122543147): use a movalbe wrapper for token
-    native_handle_t* token = b1->Duplicate();
-    ASSERT_TRUE(token);
+    sp<NativeHandle> token = b1->duplicate();
+    ASSERT_THAT(token, NotNull());
 
-    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
-    native_handle_close(token);
-    native_handle_delete(token);
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::import(token);
 
     ASSERT_THAT(b2, NotNull());
-    ASSERT_NE(b1->client_state_mask(), b2->client_state_mask());
+    ASSERT_NE(b1->clientStateMask(), b2->clientStateMask());
 
-    ASSERT_EQ(b1->Post(), 0);
-    EXPECT_EQ(b2->Acquire(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    EXPECT_EQ(b2->acquire(), 0);
 }
 
 TEST_F(BufferHubBufferTest, createNewConsumerAfterPost) {
     // Create a poducer buffer and post.
     std::unique_ptr<BufferHubBuffer> b1 =
-            BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+            BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                     kUserMetadataSize);
-    ASSERT_EQ(b1->Gain(), 0);
-    ASSERT_EQ(b1->Post(), 0);
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
 
     // Create a consumer of the buffer and test if the consumer can acquire the
     // buffer if producer posts.
-    // TODO(b/122543147): use a movalbe wrapper for token
-    native_handle_t* token = b1->Duplicate();
-    ASSERT_TRUE(token);
+    sp<NativeHandle> token = b1->duplicate();
+    ASSERT_THAT(token, NotNull());
 
-    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
-    native_handle_close(token);
-    native_handle_delete(token);
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::import(token);
 
     ASSERT_THAT(b2, NotNull());
-    ASSERT_NE(b1->client_state_mask(), b2->client_state_mask());
+    ASSERT_NE(b1->clientStateMask(), b2->clientStateMask());
 
-    EXPECT_EQ(b2->Acquire(), 0);
+    EXPECT_EQ(b2->acquire(), 0);
 }
 
 } // namespace
diff --git a/libs/ui/tests/BufferHubEventFd_test.cpp b/libs/ui/tests/BufferHubEventFd_test.cpp
index 2c9aa57..ef1781f 100644
--- a/libs/ui/tests/BufferHubEventFd_test.cpp
+++ b/libs/ui/tests/BufferHubEventFd_test.cpp
@@ -35,6 +35,7 @@
 
 const int kTimeout = 100;
 const std::chrono::milliseconds kTimeoutMs(kTimeout);
+const int kTestRuns = 5;
 
 using ::testing::Contains;
 using BufferHubEventFdTest = ::testing::Test;
@@ -46,9 +47,9 @@
     ASSERT_TRUE(eventFd.isValid());
 
     base::unique_fd epollFd(epoll_create(64));
-    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
-
     ASSERT_GE(epollFd.get(), 0);
+
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
     ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
 
     std::array<epoll_event, 1> events;
@@ -59,6 +60,96 @@
 
     // The epoll fd is edge triggered, so it only responds to the eventFd once.
     EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    // Check that it can receive consecutive signal.
+    eventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    // Check that it can receive consecutive signal from a duplicated eventfd.
+    BufferHubEventFd dupEventFd(dup(eventFd.get()));
+    ASSERT_TRUE(dupEventFd.isValid());
+    dupEventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+    dupEventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testCreateEpollFdAndAddSignaledEventFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+    eventFd.signal();
+
+    base::unique_fd epollFd(epoll_create(64));
+    ASSERT_GE(epollFd.get(), 0);
+
+    // Make sure that the epoll set has not been signal yet.
+    std::array<epoll_event, 1> events;
+    ASSERT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    // Check that adding an signaled fd into this epoll set will trigger the epoll set.
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testAddSignaledEventFdToEpollFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    ASSERT_GE(epollFd.get(), 0);
+
+    eventFd.signal();
+
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testConsecutiveSignalsFromAEventFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+    base::unique_fd epollFd(epoll_create(64));
+    ASSERT_GE(epollFd.get(), 0);
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    std::array<epoll_event, 1> events;
+    for (int i = 0; i < kTestRuns; ++i) {
+        eventFd.signal();
+        EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+        EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+    }
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testConsecutiveSignalsFromADuplicatedEventFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+    base::unique_fd epollFd(epoll_create(64));
+    ASSERT_GE(epollFd.get(), 0);
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    BufferHubEventFd dupEventFd(dup(eventFd.get()));
+    ASSERT_TRUE(dupEventFd.isValid());
+
+    std::array<epoll_event, 1> events;
+    for (int i = 0; i < kTestRuns; ++i) {
+        dupEventFd.signal();
+        EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+        EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+    }
 }
 
 TEST_F(BufferHubEventFdTest, EventFd_testClear) {
diff --git a/libs/ui/tests/BufferHubMetadata_test.cpp b/libs/ui/tests/BufferHubMetadata_test.cpp
index b7f0b4b..eb978ca 100644
--- a/libs/ui/tests/BufferHubMetadata_test.cpp
+++ b/libs/ui/tests/BufferHubMetadata_test.cpp
@@ -25,74 +25,73 @@
 class BufferHubMetadataTest : public ::testing::Test {};
 
 TEST_F(BufferHubMetadataTest, Create_UserMetdataSizeTooBig) {
-  BufferHubMetadata m1 =
-      BufferHubMetadata::Create(std::numeric_limits<uint32_t>::max());
-  EXPECT_FALSE(m1.IsValid());
+    BufferHubMetadata m1 = BufferHubMetadata::create(std::numeric_limits<uint32_t>::max());
+    EXPECT_FALSE(m1.isValid());
 }
 
 TEST_F(BufferHubMetadataTest, Create_Success) {
-  BufferHubMetadata m1 = BufferHubMetadata::Create(kEmptyUserMetadataSize);
-  EXPECT_TRUE(m1.IsValid());
-  EXPECT_NE(m1.metadata_header(), nullptr);
+    BufferHubMetadata m1 = BufferHubMetadata::create(kEmptyUserMetadataSize);
+    EXPECT_TRUE(m1.isValid());
+    EXPECT_NE(m1.metadataHeader(), nullptr);
 }
 
 TEST_F(BufferHubMetadataTest, Import_Success) {
-  BufferHubMetadata m1 = BufferHubMetadata::Create(kEmptyUserMetadataSize);
-  EXPECT_TRUE(m1.IsValid());
-  EXPECT_NE(m1.metadata_header(), nullptr);
+    BufferHubMetadata m1 = BufferHubMetadata::create(kEmptyUserMetadataSize);
+    EXPECT_TRUE(m1.isValid());
+    EXPECT_NE(m1.metadataHeader(), nullptr);
 
-  unique_fd h2 = unique_fd(dup(m1.ashmem_fd().get()));
-  EXPECT_NE(h2.get(), -1);
+    unique_fd h2 = unique_fd(dup(m1.ashmemFd().get()));
+    EXPECT_NE(h2.get(), -1);
 
-  BufferHubMetadata m2 = BufferHubMetadata::Import(std::move(h2));
-  EXPECT_EQ(h2.get(), -1);
-  EXPECT_TRUE(m1.IsValid());
-  BufferHubDefs::MetadataHeader* mh1 = m1.metadata_header();
-  EXPECT_NE(mh1, nullptr);
+    BufferHubMetadata m2 = BufferHubMetadata::import(std::move(h2));
+    EXPECT_EQ(h2.get(), -1);
+    EXPECT_TRUE(m1.isValid());
+    BufferHubDefs::MetadataHeader* mh1 = m1.metadataHeader();
+    EXPECT_NE(mh1, nullptr);
 
-  // Check if the newly allocated buffer is initialized in released state (i.e.
-  // state equals to 0U).
-  EXPECT_TRUE(mh1->buffer_state.load() == 0U);
+    // Check if the newly allocated buffer is initialized in released state (i.e.
+    // state equals to 0U).
+    EXPECT_TRUE(mh1->bufferState.load() == 0U);
 
-  EXPECT_TRUE(m2.IsValid());
-  BufferHubDefs::MetadataHeader* mh2 = m2.metadata_header();
-  EXPECT_NE(mh2, nullptr);
+    EXPECT_TRUE(m2.isValid());
+    BufferHubDefs::MetadataHeader* mh2 = m2.metadataHeader();
+    EXPECT_NE(mh2, nullptr);
 
-  // Check if the newly allocated buffer is initialized in released state (i.e.
-  // state equals to 0U).
-  EXPECT_TRUE(mh2->buffer_state.load() == 0U);
+    // Check if the newly allocated buffer is initialized in released state (i.e.
+    // state equals to 0U).
+    EXPECT_TRUE(mh2->bufferState.load() == 0U);
 }
 
 TEST_F(BufferHubMetadataTest, MoveMetadataInvalidatesOldOne) {
-  BufferHubMetadata m1 = BufferHubMetadata::Create(sizeof(int));
-  EXPECT_TRUE(m1.IsValid());
-  EXPECT_NE(m1.metadata_header(), nullptr);
-  EXPECT_NE(m1.ashmem_fd().get(), -1);
-  EXPECT_EQ(m1.user_metadata_size(), sizeof(int));
+    BufferHubMetadata m1 = BufferHubMetadata::create(sizeof(int));
+    EXPECT_TRUE(m1.isValid());
+    EXPECT_NE(m1.metadataHeader(), nullptr);
+    EXPECT_NE(m1.ashmemFd().get(), -1);
+    EXPECT_EQ(m1.userMetadataSize(), sizeof(int));
 
-  BufferHubMetadata m2 = std::move(m1);
+    BufferHubMetadata m2 = std::move(m1);
 
-  // After the move, the metadata header (a raw pointer) should be reset in the older buffer.
-  EXPECT_EQ(m1.metadata_header(), nullptr);
-  EXPECT_NE(m2.metadata_header(), nullptr);
+    // After the move, the metadata header (a raw pointer) should be reset in the older buffer.
+    EXPECT_EQ(m1.metadataHeader(), nullptr);
+    EXPECT_NE(m2.metadataHeader(), nullptr);
 
-  EXPECT_EQ(m1.ashmem_fd().get(), -1);
-  EXPECT_NE(m2.ashmem_fd().get(), -1);
+    EXPECT_EQ(m1.ashmemFd().get(), -1);
+    EXPECT_NE(m2.ashmemFd().get(), -1);
 
-  EXPECT_EQ(m1.user_metadata_size(), 0U);
-  EXPECT_EQ(m2.user_metadata_size(), sizeof(int));
+    EXPECT_EQ(m1.userMetadataSize(), 0U);
+    EXPECT_EQ(m2.userMetadataSize(), sizeof(int));
 
-  BufferHubMetadata m3{std::move(m2)};
+    BufferHubMetadata m3{std::move(m2)};
 
-  // After the move, the metadata header (a raw pointer) should be reset in the older buffer.
-  EXPECT_EQ(m2.metadata_header(), nullptr);
-  EXPECT_NE(m3.metadata_header(), nullptr);
+    // After the move, the metadata header (a raw pointer) should be reset in the older buffer.
+    EXPECT_EQ(m2.metadataHeader(), nullptr);
+    EXPECT_NE(m3.metadataHeader(), nullptr);
 
-  EXPECT_EQ(m2.ashmem_fd().get(), -1);
-  EXPECT_NE(m3.ashmem_fd().get(), -1);
+    EXPECT_EQ(m2.ashmemFd().get(), -1);
+    EXPECT_NE(m3.ashmemFd().get(), -1);
 
-  EXPECT_EQ(m2.user_metadata_size(), 0U);
-  EXPECT_EQ(m3.user_metadata_size(), sizeof(int));
+    EXPECT_EQ(m2.userMetadataSize(), 0U);
+    EXPECT_EQ(m3.userMetadataSize(), sizeof(int));
 }
 
 }  // namespace dvr
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index 5b46454..c767ce0 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -37,10 +37,10 @@
 
 TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) {
     std::unique_ptr<BufferHubBuffer> b1 =
-            BufferHubBuffer::Create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
+            BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
                                     kTestUsage, /*userMetadataSize=*/0);
     ASSERT_NE(b1, nullptr);
-    EXPECT_TRUE(b1->IsValid());
+    EXPECT_TRUE(b1->isValid());
 
     sp<GraphicBuffer> gb(new GraphicBuffer(std::move(b1)));
     EXPECT_TRUE(gb->isBufferHubBuffer());
@@ -61,10 +61,10 @@
 
 TEST_F(GraphicBufferTest, BufferIdMatchesBufferHubBufferId) {
     std::unique_ptr<BufferHubBuffer> b1 =
-            BufferHubBuffer::Create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
+            BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
                                     kTestUsage, /*userMetadataSize=*/0);
     EXPECT_NE(b1, nullptr);
-    EXPECT_TRUE(b1->IsValid());
+    EXPECT_TRUE(b1->isValid());
 
     int b1_id = b1->id();
     EXPECT_GE(b1_id, 0);
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 527a27d..27ab024 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -20,12 +20,12 @@
     return result;                            \
   })()
 
-using android::BufferHubDefs::AnyClientAcquired;
-using android::BufferHubDefs::AnyClientGained;
-using android::BufferHubDefs::AnyClientPosted;
-using android::BufferHubDefs::IsClientAcquired;
-using android::BufferHubDefs::IsClientPosted;
-using android::BufferHubDefs::IsClientReleased;
+using android::BufferHubDefs::isAnyClientAcquired;
+using android::BufferHubDefs::isAnyClientGained;
+using android::BufferHubDefs::isAnyClientPosted;
+using android::BufferHubDefs::isClientAcquired;
+using android::BufferHubDefs::isClientPosted;
+using android::BufferHubDefs::isClientReleased;
 using android::BufferHubDefs::kFirstClientBitMask;
 using android::dvr::ConsumerBuffer;
 using android::dvr::ProducerBuffer;
@@ -268,7 +268,7 @@
   // Post in gained state should succeed.
   EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
   EXPECT_EQ(p->buffer_state(), c->buffer_state());
-  EXPECT_TRUE(AnyClientPosted(p->buffer_state()));
+  EXPECT_TRUE(isAnyClientPosted(p->buffer_state()));
 
   // Post and gain in posted state should fail.
   EXPECT_EQ(-EBUSY, p->PostAsync(&metadata, invalid_fence));
@@ -280,7 +280,7 @@
   EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
   EXPECT_FALSE(invalid_fence.IsValid());
   EXPECT_EQ(p->buffer_state(), c->buffer_state());
-  EXPECT_TRUE(AnyClientAcquired(p->buffer_state()));
+  EXPECT_TRUE(isAnyClientAcquired(p->buffer_state()));
 
   // Acquire, post, and gain in acquired state should fail.
   EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
@@ -304,7 +304,7 @@
   EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
   EXPECT_FALSE(invalid_fence.IsValid());
   EXPECT_EQ(p->buffer_state(), c->buffer_state());
-  EXPECT_TRUE(AnyClientGained(p->buffer_state()));
+  EXPECT_TRUE(isAnyClientGained(p->buffer_state()));
 
   // Acquire and gain in gained state should fail.
   EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
@@ -329,7 +329,7 @@
   ASSERT_TRUE(c.get() != nullptr);
   ASSERT_EQ(0, p->GainAsync());
   ASSERT_EQ(0, p->Post(LocalHandle()));
-  ASSERT_TRUE(AnyClientPosted(p->buffer_state()));
+  ASSERT_TRUE(isAnyClientPosted(p->buffer_state()));
 
   // Gain in posted state should only succeed with gain_posted_buffer = true.
   LocalHandle invalid_fence;
@@ -346,7 +346,7 @@
   ASSERT_TRUE(c.get() != nullptr);
   ASSERT_EQ(0, p->GainAsync());
   ASSERT_EQ(0, p->Post(LocalHandle()));
-  ASSERT_TRUE(AnyClientPosted(p->buffer_state()));
+  ASSERT_TRUE(isAnyClientPosted(p->buffer_state()));
 
   // GainAsync in posted state should only succeed with gain_posted_buffer
   // equals true.
@@ -364,9 +364,9 @@
   ASSERT_EQ(0, p->Post(LocalHandle()));
   // Producer state bit is in released state after post, other clients shall be
   // in posted state although there is no consumer of this buffer yet.
-  ASSERT_TRUE(IsClientReleased(p->buffer_state(), p->client_state_mask()));
+  ASSERT_TRUE(isClientReleased(p->buffer_state(), p->client_state_mask()));
   ASSERT_TRUE(p->is_released());
-  ASSERT_TRUE(AnyClientPosted(p->buffer_state()));
+  ASSERT_TRUE(isAnyClientPosted(p->buffer_state()));
 
   // Gain in released state should succeed.
   LocalHandle invalid_fence;
@@ -393,14 +393,14 @@
 
   // Post the producer should trigger all consumers to be available.
   EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
-  EXPECT_TRUE(IsClientReleased(p->buffer_state(), p->client_state_mask()));
+  EXPECT_TRUE(isClientReleased(p->buffer_state(), p->client_state_mask()));
   for (size_t i = 0; i < kMaxConsumerCount; ++i) {
     EXPECT_TRUE(
-        IsClientPosted(cs[i]->buffer_state(), cs[i]->client_state_mask()));
+        isClientPosted(cs[i]->buffer_state(), cs[i]->client_state_mask()));
     EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(cs[i])));
     EXPECT_EQ(0, cs[i]->AcquireAsync(&metadata, &invalid_fence));
     EXPECT_TRUE(
-        IsClientAcquired(p->buffer_state(), cs[i]->client_state_mask()));
+        isClientAcquired(p->buffer_state(), cs[i]->client_state_mask()));
   }
 
   // All consumers have to release before the buffer is considered to be
@@ -424,22 +424,22 @@
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
   EXPECT_EQ(0, p->GainAsync());
-  EXPECT_TRUE(AnyClientGained(p->buffer_state()));
+  EXPECT_TRUE(isAnyClientGained(p->buffer_state()));
 
   std::unique_ptr<ConsumerBuffer> c =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
-  EXPECT_TRUE(AnyClientGained(c->buffer_state()));
+  EXPECT_TRUE(isAnyClientGained(c->buffer_state()));
 
   DvrNativeBufferMetadata metadata;
   LocalHandle invalid_fence;
 
   // Post the gained buffer should signal already created consumer.
   EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
-  EXPECT_TRUE(AnyClientPosted(p->buffer_state()));
+  EXPECT_TRUE(isAnyClientPosted(p->buffer_state()));
   EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
   EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
-  EXPECT_TRUE(AnyClientAcquired(c->buffer_state()));
+  EXPECT_TRUE(isAnyClientAcquired(c->buffer_state()));
 }
 
 TEST_F(LibBufferHubTest, TestCreateTheFirstConsumerAfterPostingBuffer) {
@@ -447,7 +447,7 @@
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p.get() != nullptr);
   EXPECT_EQ(0, p->GainAsync());
-  EXPECT_TRUE(AnyClientGained(p->buffer_state()));
+  EXPECT_TRUE(isAnyClientGained(p->buffer_state()));
 
   DvrNativeBufferMetadata metadata;
   LocalHandle invalid_fence;
@@ -462,7 +462,7 @@
   std::unique_ptr<ConsumerBuffer> c =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
-  EXPECT_TRUE(IsClientPosted(c->buffer_state(), c->client_state_mask()));
+  EXPECT_TRUE(isClientPosted(c->buffer_state(), c->client_state_mask()));
   EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
 }
 
@@ -500,7 +500,7 @@
 
   EXPECT_TRUE(p->is_released());
   EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
-  EXPECT_TRUE(AnyClientGained(p->buffer_state()));
+  EXPECT_TRUE(isAnyClientGained(p->buffer_state()));
 }
 
 TEST_F(LibBufferHubTest, TestWithCustomMetadata) {
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index b28d101..17930b4 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -122,15 +122,15 @@
   // are mapped from shared memory as an atomic object. The std::atomic's
   // constructor will not be called so that the original value stored in the
   // memory region will be preserved.
-  buffer_state_ = &metadata_header_->buffer_state;
+  buffer_state_ = &metadata_header_->bufferState;
   ALOGD_IF(TRACE,
            "BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx32 ".",
            id(), buffer_state_->load(std::memory_order_acquire));
-  fence_state_ = &metadata_header_->fence_state;
+  fence_state_ = &metadata_header_->fenceState;
   ALOGD_IF(TRACE,
            "BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx32 ".", id(),
            fence_state_->load(std::memory_order_acquire));
-  active_clients_bit_mask_ = &metadata_header_->active_clients_bit_mask;
+  active_clients_bit_mask_ = &metadata_header_->activeClientsBitMask;
   ALOGD_IF(
       TRACE,
       "BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx32
diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp
index b6ca64e..115e866 100644
--- a/libs/vr/libbufferhub/consumer_buffer.cpp
+++ b/libs/vr/libbufferhub/consumer_buffer.cpp
@@ -38,7 +38,7 @@
   // The buffer can be acquired iff the buffer state for this client is posted.
   uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
-  if (!BufferHubDefs::IsClientPosted(current_buffer_state,
+  if (!BufferHubDefs::isClientPosted(current_buffer_state,
                                      client_state_mask())) {
     ALOGE(
         "%s: Failed to acquire the buffer. The buffer is not posted, id=%d "
@@ -58,7 +58,7 @@
         " when trying to acquire the buffer and modify the buffer state to "
         "%" PRIx32 ". About to try again if the buffer is still posted.",
         __FUNCTION__, current_buffer_state, updated_buffer_state);
-    if (!BufferHubDefs::IsClientPosted(current_buffer_state,
+    if (!BufferHubDefs::isClientPosted(current_buffer_state,
                                        client_state_mask())) {
       ALOGE(
           "%s: Failed to acquire the buffer. The buffer is no longer posted, "
@@ -144,7 +144,7 @@
   // released state.
   uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
-  if (BufferHubDefs::IsClientReleased(current_buffer_state,
+  if (BufferHubDefs::isClientReleased(current_buffer_state,
                                       client_state_mask())) {
     return 0;
   }
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index fa39d08..8a490d9 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -97,8 +97,8 @@
   uint32_t usage() const { return buffer_.usage(); }
   uint32_t layer_count() const { return buffer_.layer_count(); }
 
-  uint64_t GetQueueIndex() const { return metadata_header_->queue_index; }
-  void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; }
+  uint64_t GetQueueIndex() const { return metadata_header_->queueIndex; }
+  void SetQueueIndex(uint64_t index) { metadata_header_->queueIndex = index; }
 
  protected:
   explicit BufferHubBase(LocalChannelHandle channel);
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index bab7367..e610e18 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -27,38 +27,38 @@
 static constexpr uint32_t kFirstClientBitMask =
     android::BufferHubDefs::kFirstClientBitMask;
 
-static inline bool AnyClientGained(uint32_t state) {
-  return android::BufferHubDefs::AnyClientGained(state);
+static inline bool isAnyClientGained(uint32_t state) {
+  return android::BufferHubDefs::isAnyClientGained(state);
 }
 
-static inline bool IsClientGained(uint32_t state, uint32_t client_bit_mask) {
-  return android::BufferHubDefs::IsClientGained(state, client_bit_mask);
+static inline bool isClientGained(uint32_t state, uint32_t client_bit_mask) {
+  return android::BufferHubDefs::isClientGained(state, client_bit_mask);
 }
 
-static inline bool AnyClientPosted(uint32_t state) {
-  return android::BufferHubDefs::AnyClientPosted(state);
+static inline bool isAnyClientPosted(uint32_t state) {
+  return android::BufferHubDefs::isAnyClientPosted(state);
 }
 
-static inline bool IsClientPosted(uint32_t state, uint32_t client_bit_mask) {
-  return android::BufferHubDefs::IsClientPosted(state, client_bit_mask);
+static inline bool isClientPosted(uint32_t state, uint32_t client_bit_mask) {
+  return android::BufferHubDefs::isClientPosted(state, client_bit_mask);
 }
 
-static inline bool AnyClientAcquired(uint32_t state) {
-  return android::BufferHubDefs::AnyClientAcquired(state);
+static inline bool isAnyClientAcquired(uint32_t state) {
+  return android::BufferHubDefs::isAnyClientAcquired(state);
 }
 
-static inline bool IsClientAcquired(uint32_t state, uint32_t client_bit_mask) {
-  return android::BufferHubDefs::IsClientAcquired(state, client_bit_mask);
+static inline bool isClientAcquired(uint32_t state, uint32_t client_bit_mask) {
+  return android::BufferHubDefs::isClientAcquired(state, client_bit_mask);
 }
 
-static inline bool IsClientReleased(uint32_t state, uint32_t client_bit_mask) {
-  return android::BufferHubDefs::IsClientReleased(state, client_bit_mask);
+static inline bool isClientReleased(uint32_t state, uint32_t client_bit_mask) {
+  return android::BufferHubDefs::isClientReleased(state, client_bit_mask);
 }
 
 // Returns the next available buffer client's client_state_masks.
 // @params union_bits. Union of all existing clients' client_state_masks.
-static inline uint32_t FindNextAvailableClientStateMask(uint32_t union_bits) {
-  return android::BufferHubDefs::FindNextAvailableClientStateMask(union_bits);
+static inline uint32_t findNextAvailableClientStateMask(uint32_t union_bits) {
+  return android::BufferHubDefs::findNextAvailableClientStateMask(union_bits);
 }
 
 using MetadataHeader = android::BufferHubDefs::MetadataHeader;
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index edfdddf..3d88ba5 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -82,7 +82,7 @@
   // The buffer can be posted iff the buffer state for this client is gained.
   uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
-  if (!BufferHubDefs::IsClientGained(current_buffer_state,
+  if (!BufferHubDefs::isClientGained(current_buffer_state,
                                      client_state_mask())) {
     ALOGE("%s: not gained, id=%d state=%" PRIx32 ".", __FUNCTION__, id(),
           current_buffer_state);
@@ -103,7 +103,7 @@
         "%" PRIx32
         ". About to try again if the buffer is still gained by this client.",
         __FUNCTION__, current_buffer_state, updated_buffer_state);
-    if (!BufferHubDefs::IsClientGained(current_buffer_state,
+    if (!BufferHubDefs::isClientGained(current_buffer_state,
                                        client_state_mask())) {
       ALOGE(
           "%s: Failed to post the buffer. The buffer is no longer gained, "
@@ -166,14 +166,14 @@
   ALOGD_IF(TRACE, "%s: buffer=%d, state=%" PRIx32 ".", __FUNCTION__, id(),
            current_buffer_state);
 
-  if (BufferHubDefs::IsClientGained(current_buffer_state,
+  if (BufferHubDefs::isClientGained(current_buffer_state,
                                     client_state_mask())) {
     ALOGV("%s: already gained id=%d.", __FUNCTION__, id());
     return 0;
   }
-  if (BufferHubDefs::AnyClientAcquired(current_buffer_state) ||
-      BufferHubDefs::AnyClientGained(current_buffer_state) ||
-      (BufferHubDefs::AnyClientPosted(
+  if (BufferHubDefs::isAnyClientAcquired(current_buffer_state) ||
+      BufferHubDefs::isAnyClientGained(current_buffer_state) ||
+      (BufferHubDefs::isAnyClientPosted(
            current_buffer_state &
            active_clients_bit_mask_->load(std::memory_order_acquire)) &&
        !gain_posted_buffer)) {
@@ -195,9 +195,9 @@
         "clients.",
         __FUNCTION__, current_buffer_state, updated_buffer_state);
 
-    if (BufferHubDefs::AnyClientAcquired(current_buffer_state) ||
-        BufferHubDefs::AnyClientGained(current_buffer_state) ||
-        (BufferHubDefs::AnyClientPosted(
+    if (BufferHubDefs::isAnyClientAcquired(current_buffer_state) ||
+        BufferHubDefs::isAnyClientGained(current_buffer_state) ||
+        (BufferHubDefs::isAnyClientPosted(
              current_buffer_state &
              active_clients_bit_mask_->load(std::memory_order_acquire)) &&
          !gain_posted_buffer)) {
@@ -291,7 +291,7 @@
   // TODO(b/112338294) Keep here for reference. Remove it after new logic is
   // written.
   /* uint32_t buffer_state = buffer_state_->load(std::memory_order_acquire);
-  if (!BufferHubDefs::IsClientGained(
+  if (!BufferHubDefs::isClientGained(
       buffer_state, BufferHubDefs::kFirstClientStateMask)) {
     // Can only detach a ProducerBuffer when it's in gained state.
     ALOGW("ProducerBuffer::Detach: The buffer (id=%d, state=0x%" PRIx32
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index d7833f3..2d3fa4a 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -532,7 +532,7 @@
 Status<size_t> ProducerQueue::InsertBuffer(
     const std::shared_ptr<ProducerBuffer>& buffer) {
   if (buffer == nullptr ||
-      !BufferHubDefs::IsClientGained(buffer->buffer_state(),
+      !BufferHubDefs::isClientGained(buffer->buffer_state(),
                                      buffer->client_state_mask())) {
     ALOGE(
         "ProducerQueue::InsertBuffer: Can only insert a buffer when it's in "
@@ -638,7 +638,7 @@
             static_cast<int>(*slot));
       return ErrorStatus(EIO);
     }
-    if (!BufferHubDefs::AnyClientAcquired(buffer->buffer_state())) {
+    if (!BufferHubDefs::isAnyClientAcquired(buffer->buffer_state())) {
       *slot = *iter;
       unavailable_buffers_slot_.erase(iter);
       unavailable_buffers_slot_.push_back(*slot);
diff --git a/opengl/libagl/Android.bp b/opengl/libagl/Android.bp
new file mode 100644
index 0000000..6ec24b3
--- /dev/null
+++ b/opengl/libagl/Android.bp
@@ -0,0 +1,99 @@
+//
+// Build the software OpenGL ES library
+//
+
+cc_defaults {
+    name: "libGLES_android_defaults",
+
+    cflags: [
+        "-DLOG_TAG=\"libagl\"",
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+        "-fvisibility=hidden",
+        "-Wall",
+        "-Werror",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "libhardware",
+        "libutils",
+        "liblog",
+        "libpixelflinger",
+        "libETC1",
+        "libui",
+        "libnativewindow",
+    ],
+
+    // we need to access the private Bionic header <bionic_tls.h>
+    include_dirs: ["bionic/libc/private"],
+
+    arch: {
+        arm: {
+            cflags: ["-fstrict-aliasing"],
+        },
+
+        mips: {
+            cflags: [
+                "-fstrict-aliasing",
+                // The graphics code can generate division by zero
+                "-mno-check-zero-division",
+            ],
+        },
+    },
+}
+
+cc_library_shared {
+    name: "libGLES_android",
+    defaults: ["libGLES_android_defaults"],
+
+    whole_static_libs: ["libGLES_android_arm"],
+
+    srcs: [
+        "egl.cpp",
+        "state.cpp",
+        "texture.cpp",
+        "Tokenizer.cpp",
+        "TokenManager.cpp",
+        "TextureObjectManager.cpp",
+        "BufferObjectManager.cpp",
+    ],
+
+    arch: {
+        arm: {
+            srcs: [
+                "fixed_asm.S",
+                "iterators.S",
+            ],
+        },
+
+        mips: {
+            rev6: {
+                srcs: ["arch-mips/fixed_asm.S"],
+            },
+        },
+    },
+
+    relative_install_path: "egl",
+}
+
+cc_library_static {
+    name: "libGLES_android_arm",
+    defaults: ["libGLES_android_defaults"],
+
+    srcs: [
+        "array.cpp",
+        "fp.cpp",
+        "light.cpp",
+        "matrix.cpp",
+        "mipmap.cpp",
+        "primitives.cpp",
+        "vertex.cpp",
+    ],
+
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+}
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
deleted file mode 100644
index 15a12e4..0000000
--- a/opengl/libagl/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#
-# Build the software OpenGL ES library
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	egl.cpp                     \
-	state.cpp		            \
-	texture.cpp		            \
-    Tokenizer.cpp               \
-    TokenManager.cpp            \
-    TextureObjectManager.cpp    \
-    BufferObjectManager.cpp     \
-	array.cpp.arm		        \
-	fp.cpp.arm		            \
-	light.cpp.arm		        \
-	matrix.cpp.arm		        \
-	mipmap.cpp.arm		        \
-	primitives.cpp.arm	        \
-	vertex.cpp.arm
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libagl\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger libETC1 libui libnativewindow
-
-LOCAL_SRC_FILES_arm += fixed_asm.S iterators.S
-LOCAL_CFLAGS_arm += -fstrict-aliasing
-
-ifndef ARCH_MIPS_REV6
-LOCAL_SRC_FILES_mips += arch-mips/fixed_asm.S
-endif
-LOCAL_CFLAGS_mips += -fstrict-aliasing
-# The graphics code can generate division by zero
-LOCAL_CFLAGS_mips += -mno-check-zero-division
-
-LOCAL_CFLAGS += -Wall -Werror
-
-# we need to access the private Bionic header <bionic_tls.h>
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_MODULE_RELATIVE_PATH := egl
-LOCAL_MODULE:= libGLES_android
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index c80b79a..c0bace8 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -154,8 +154,8 @@
         "libbase",
         "libhidlbase",
         "libhidltransport",
-        "libnativebridge",
-        "libnativeloader",
+        "libnativebridge_lazy",
+        "libnativeloader_lazy",
         "libutils",
     ],
     static_libs: [
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 8a409ae..259242b 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -27,6 +27,7 @@
 #include <android/dlext.h>
 #include <cutils/properties.h>
 #include <log/log.h>
+#include <utils/Timers.h>
 
 #ifndef __ANDROID_VNDK__
 #include <graphicsenv/GraphicsEnv.h>
@@ -217,6 +218,7 @@
 void* Loader::open(egl_connection_t* cnx)
 {
     ATRACE_CALL();
+    const nsecs_t openTime = systemTime();
 
     void* dso;
     driver_t* hnd = nullptr;
@@ -234,6 +236,8 @@
     if (dso) {
         hnd = new driver_t(dso);
     } else {
+        android::GraphicsEnv::getInstance().clearDriverLoadingInfo(
+                android::GraphicsEnv::Api::API_GL);
         // Always load EGL first
         dso = load_driver("EGL", cnx, EGL);
         if (dso) {
@@ -243,18 +247,31 @@
         }
     }
 
+    if (!hnd) {
+        android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL,
+                                                            false, systemTime() - openTime);
+    }
+
     LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation");
 
     cnx->libEgl   = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
     cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
     cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
 
+    if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) {
+        android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL,
+                                                            false, systemTime() - openTime);
+    }
+
     LOG_ALWAYS_FATAL_IF(!cnx->libEgl,
             "couldn't load system EGL wrapper libraries");
 
     LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1,
             "couldn't load system OpenGL ES wrapper libraries");
 
+    android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL, true,
+                                                        systemTime() - openTime);
+
     return (void*)hnd;
 }
 
@@ -589,17 +606,21 @@
     void* dso = nullptr;
     android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
     if (ns) {
+        android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::ANGLE);
         dso = load_angle(kind, ns, cnx);
     }
 #ifndef __ANDROID_VNDK__
     if (!dso) {
         android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
         if (ns) {
+            android::GraphicsEnv::getInstance().setDriverToLoad(
+                    android::GraphicsEnv::Driver::GL_UPDATED);
             dso = load_updated_driver(kind, ns);
         }
     }
 #endif
     if (!dso) {
+        android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL);
         dso = load_system_driver(kind);
         if (!dso)
             return nullptr;
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 79166a7..872631f 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -954,6 +954,22 @@
             egl_context_t* const c = get_context(share_list);
             share_list = c->context;
         }
+        // b/111083885 - If we are presenting EGL 1.4 interface to apps
+        // error out on robust access attributes that are invalid
+        // in EGL 1.4 as the driver may be fine with them but dEQP expects
+        // tests to fail according to spec.
+        if (attrib_list && (cnx->driverVersion < EGL_MAKE_VERSION(1, 5, 0))) {
+            const EGLint* attrib_ptr = attrib_list;
+            while (*attrib_ptr != EGL_NONE) {
+                GLint attr = *attrib_ptr++;
+                GLint value = *attrib_ptr++;
+                if (attr == EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR) {
+                    // We are GL ES context with EGL 1.4, this is an invalid
+                    // attribute
+                    return setError(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
+                }
+            };
+        }
         EGLContext context = cnx->egl.eglCreateContext(
                 dp->disp.dpy, config, share_list, attrib_list);
         if (context != EGL_NO_CONTEXT) {
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index b06422a..a0bd4e2 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -34,8 +34,12 @@
     }
 
     // Get main display parameters.
-    sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
-            ISurfaceComposer::eDisplayIdMain);
+    const auto mainDpy = SurfaceComposerClient::getInternalDisplayToken();
+    if (mainDpy == nullptr) {
+        fprintf(stderr, "ERROR: no display\n");
+        return;
+    }
+
     DisplayInfo mainDpyInfo;
     err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
     if (err != NO_ERROR) {
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index 6b802fb..7a3472f 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -53,7 +53,7 @@
             std::make_shared<BufferNode>(desc.width, desc.height, desc.layers, desc.format,
                                          desc.usage, userMetadataSize,
                                          BufferHubIdGenerator::getInstance().getId());
-    if (node == nullptr || !node->IsValid()) {
+    if (node == nullptr || !node->isValid()) {
         ALOGE("%s: creating BufferNode failed.", __FUNCTION__);
         _hidl_cb(/*status=*/BufferHubStatus::ALLOCATION_FAILED, /*bufferClient=*/nullptr,
                  /*bufferTraits=*/{});
@@ -70,11 +70,17 @@
     NATIVE_HANDLE_DECLARE_STORAGE(bufferInfoStorage, BufferHubDefs::kBufferInfoNumFds,
                                   BufferHubDefs::kBufferInfoNumInts);
     hidl_handle bufferInfo =
-            buildBufferInfo(bufferInfoStorage, node->id(), node->AddNewActiveClientsBitToMask(),
-                            node->user_metadata_size(), node->metadata().ashmem_fd(),
+            buildBufferInfo(bufferInfoStorage, node->id(), node->addNewActiveClientsBitToMask(),
+                            node->userMetadataSize(), node->metadata().ashmemFd(),
                             node->eventFd().get());
-    BufferTraits bufferTraits = {/*bufferDesc=*/description,
-                                 /*bufferHandle=*/hidl_handle(node->buffer_handle()),
+    // During the gralloc allocation carried out by BufferNode, gralloc allocator will populate the
+    // fields of its HardwareBufferDescription (i.e. strides) according to the actual
+    // gralloc implementation. We need to read those fields back and send them to the client via
+    // BufferTraits.
+    HardwareBufferDescription allocatedBufferDesc;
+    memcpy(&allocatedBufferDesc, &node->bufferDesc(), sizeof(AHardwareBuffer_Desc));
+    BufferTraits bufferTraits = {/*bufferDesc=*/allocatedBufferDesc,
+                                 /*bufferHandle=*/hidl_handle(node->bufferHandle()),
                                  /*bufferInfo=*/std::move(bufferInfo)};
 
     _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
@@ -141,7 +147,7 @@
     }
 
     sp<BufferClient> client = new BufferClient(*originClient);
-    uint32_t clientStateMask = client->getBufferNode()->AddNewActiveClientsBitToMask();
+    uint32_t clientStateMask = client->getBufferNode()->addNewActiveClientsBitToMask();
     if (clientStateMask == 0U) {
         // Reach max client count
         ALOGE("%s: import failed, BufferNode#%u reached maximum clients.", __FUNCTION__,
@@ -157,17 +163,17 @@
     std::shared_ptr<BufferNode> node = client->getBufferNode();
 
     HardwareBufferDescription bufferDesc;
-    memcpy(&bufferDesc, &node->buffer_desc(), sizeof(HardwareBufferDescription));
+    memcpy(&bufferDesc, &node->bufferDesc(), sizeof(HardwareBufferDescription));
 
     // Allocate memory for bufferInfo of type hidl_handle on the stack. See
     // http://aosp/286282 for the usage of NATIVE_HANDLE_DECLARE_STORAGE.
     NATIVE_HANDLE_DECLARE_STORAGE(bufferInfoStorage, BufferHubDefs::kBufferInfoNumFds,
                                   BufferHubDefs::kBufferInfoNumInts);
     hidl_handle bufferInfo = buildBufferInfo(bufferInfoStorage, node->id(), clientStateMask,
-                                             node->user_metadata_size(),
-                                             node->metadata().ashmem_fd(), node->eventFd().get());
+                                             node->userMetadataSize(), node->metadata().ashmemFd(),
+                                             node->eventFd().get());
     BufferTraits bufferTraits = {/*bufferDesc=*/bufferDesc,
-                                 /*bufferHandle=*/hidl_handle(node->buffer_handle()),
+                                 /*bufferHandle=*/hidl_handle(node->bufferHandle()),
                                  /*bufferInfo=*/std::move(bufferInfo)};
 
     _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
@@ -231,12 +237,12 @@
     for (auto iter = clientCount.begin(); iter != clientCount.end(); ++iter) {
         const std::shared_ptr<BufferNode> node = std::move(iter->second.first);
         const uint32_t clientCount = iter->second.second;
-        AHardwareBuffer_Desc desc = node->buffer_desc();
+        AHardwareBuffer_Desc desc = node->bufferDesc();
 
         MetadataHeader* metadataHeader =
-                const_cast<BufferHubMetadata*>(&node->metadata())->metadata_header();
-        const uint32_t state = metadataHeader->buffer_state.load(std::memory_order_acquire);
-        const uint64_t index = metadataHeader->queue_index;
+                const_cast<BufferHubMetadata*>(&node->metadata())->metadataHeader();
+        const uint32_t state = metadataHeader->bufferState.load(std::memory_order_acquire);
+        const uint64_t index = metadataHeader->queueIndex;
 
         stream << std::right;
         stream << std::setw(6) << /*Id=*/node->id();
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index 5106390..04ca649 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -11,62 +11,61 @@
 namespace V1_0 {
 namespace implementation {
 
-void BufferNode::InitializeMetadata() {
+void BufferNode::initializeMetadata() {
     // Using placement new here to reuse shared memory instead of new allocation
     // Initialize the atomic variables to zero.
-    BufferHubDefs::MetadataHeader* metadata_header = metadata_.metadata_header();
-    buffer_state_ = new (&metadata_header->buffer_state) std::atomic<uint32_t>(0);
-    fence_state_ = new (&metadata_header->fence_state) std::atomic<uint32_t>(0);
-    active_clients_bit_mask_ =
-            new (&metadata_header->active_clients_bit_mask) std::atomic<uint32_t>(0);
+    BufferHubDefs::MetadataHeader* metadataHeader = mMetadata.metadataHeader();
+    mBufferState = new (&metadataHeader->bufferState) std::atomic<uint32_t>(0);
+    mFenceState = new (&metadataHeader->fenceState) std::atomic<uint32_t>(0);
+    mActiveClientsBitMask = new (&metadataHeader->activeClientsBitMask) std::atomic<uint32_t>(0);
     // The C++ standard recommends (but does not require) that lock-free atomic operations are
     // also address-free, that is, suitable for communication between processes using shared
     // memory.
-    LOG_ALWAYS_FATAL_IF(!std::atomic_is_lock_free(buffer_state_) ||
-                                !std::atomic_is_lock_free(fence_state_) ||
-                                !std::atomic_is_lock_free(active_clients_bit_mask_),
+    LOG_ALWAYS_FATAL_IF(!std::atomic_is_lock_free(mBufferState) ||
+                                !std::atomic_is_lock_free(mFenceState) ||
+                                !std::atomic_is_lock_free(mActiveClientsBitMask),
                         "Atomic variables in ashmen are not lock free.");
 }
 
 // Allocates a new BufferNode.
-BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
-                       uint64_t usage, size_t user_metadata_size, int id)
+BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format,
+                       uint64_t usage, size_t userMetadataSize, int id)
       : mId(id) {
-    uint32_t out_stride = 0;
+    uint32_t outStride = 0;
     // graphicBufferId is not used in GraphicBufferAllocator::allocate
     // TODO(b/112338294) After move to the service folder, stop using the
     // hardcoded service name "bufferhub".
-    int ret = GraphicBufferAllocator::get().allocate(width, height, format, layer_count, usage,
+    int ret = GraphicBufferAllocator::get().allocate(width, height, format, layerCount, usage,
                                                      const_cast<const native_handle_t**>(
-                                                             &buffer_handle_),
-                                                     &out_stride,
+                                                             &mBufferHandle),
+                                                     &outStride,
                                                      /*graphicBufferId=*/0,
                                                      /*requestor=*/"bufferhub");
 
-    if (ret != OK || buffer_handle_ == nullptr) {
+    if (ret != OK || mBufferHandle == nullptr) {
         ALOGE("%s: Failed to allocate buffer: %s", __FUNCTION__, strerror(-ret));
         return;
     }
 
-    buffer_desc_.width = width;
-    buffer_desc_.height = height;
-    buffer_desc_.layers = layer_count;
-    buffer_desc_.format = format;
-    buffer_desc_.usage = usage;
-    buffer_desc_.stride = out_stride;
+    mBufferDesc.width = width;
+    mBufferDesc.height = height;
+    mBufferDesc.layers = layerCount;
+    mBufferDesc.format = format;
+    mBufferDesc.usage = usage;
+    mBufferDesc.stride = outStride;
 
-    metadata_ = BufferHubMetadata::Create(user_metadata_size);
-    if (!metadata_.IsValid()) {
+    mMetadata = BufferHubMetadata::create(userMetadataSize);
+    if (!mMetadata.isValid()) {
         ALOGE("%s: Failed to allocate metadata.", __FUNCTION__);
         return;
     }
-    InitializeMetadata();
+    initializeMetadata();
 }
 
 BufferNode::~BufferNode() {
     // Free the handle
-    if (buffer_handle_ != nullptr) {
-        status_t ret = GraphicBufferAllocator::get().free(buffer_handle_);
+    if (mBufferHandle != nullptr) {
+        status_t ret = GraphicBufferAllocator::get().free(mBufferHandle);
         if (ret != OK) {
             ALOGE("%s: Failed to free handle; Got error: %d", __FUNCTION__, ret);
         }
@@ -78,33 +77,33 @@
     }
 }
 
-uint32_t BufferNode::GetActiveClientsBitMask() const {
-    return active_clients_bit_mask_->load(std::memory_order_acquire);
+uint32_t BufferNode::getActiveClientsBitMask() const {
+    return mActiveClientsBitMask->load(std::memory_order_acquire);
 }
 
-uint32_t BufferNode::AddNewActiveClientsBitToMask() {
-    uint32_t current_active_clients_bit_mask = GetActiveClientsBitMask();
-    uint32_t client_state_mask = 0U;
-    uint32_t updated_active_clients_bit_mask = 0U;
+uint32_t BufferNode::addNewActiveClientsBitToMask() {
+    uint32_t currentActiveClientsBitMask = getActiveClientsBitMask();
+    uint32_t clientStateMask = 0U;
+    uint32_t updatedActiveClientsBitMask = 0U;
     do {
-        client_state_mask =
-                BufferHubDefs::FindNextAvailableClientStateMask(current_active_clients_bit_mask);
-        if (client_state_mask == 0U) {
+        clientStateMask =
+                BufferHubDefs::findNextAvailableClientStateMask(currentActiveClientsBitMask);
+        if (clientStateMask == 0U) {
             ALOGE("%s: reached the maximum number of channels per buffer node: %d.", __FUNCTION__,
                   BufferHubDefs::kMaxNumberOfClients);
             errno = E2BIG;
             return 0U;
         }
-        updated_active_clients_bit_mask = current_active_clients_bit_mask | client_state_mask;
-    } while (!(active_clients_bit_mask_->compare_exchange_weak(current_active_clients_bit_mask,
-                                                               updated_active_clients_bit_mask,
-                                                               std::memory_order_acq_rel,
-                                                               std::memory_order_acquire)));
-    return client_state_mask;
+        updatedActiveClientsBitMask = currentActiveClientsBitMask | clientStateMask;
+    } while (!(mActiveClientsBitMask->compare_exchange_weak(currentActiveClientsBitMask,
+                                                            updatedActiveClientsBitMask,
+                                                            std::memory_order_acq_rel,
+                                                            std::memory_order_acquire)));
+    return clientStateMask;
 }
 
-void BufferNode::RemoveClientsBitFromMask(const uint32_t& value) {
-    active_clients_bit_mask_->fetch_and(~value);
+void BufferNode::removeClientsBitFromMask(const uint32_t& value) {
+    mActiveClientsBitMask->fetch_and(~value);
 }
 
 } // namespace implementation
diff --git a/services/bufferhub/include/bufferhub/BufferClient.h b/services/bufferhub/include/bufferhub/BufferClient.h
index 66ed4bd..644b403 100644
--- a/services/bufferhub/include/bufferhub/BufferClient.h
+++ b/services/bufferhub/include/bufferhub/BufferClient.h
@@ -72,4 +72,4 @@
 } // namespace frameworks
 } // namespace android
 
-#endif
\ No newline at end of file
+#endif
diff --git a/services/bufferhub/include/bufferhub/BufferNode.h b/services/bufferhub/include/bufferhub/BufferNode.h
index 4729e1c..62a8d63 100644
--- a/services/bufferhub/include/bufferhub/BufferNode.h
+++ b/services/bufferhub/include/bufferhub/BufferNode.h
@@ -16,79 +16,79 @@
 class BufferNode {
 public:
     // Allocates a new BufferNode.
-    BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
-               uint64_t usage, size_t user_metadata_size, int id = -1);
+    BufferNode(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format,
+               uint64_t usage, size_t userMetadataSize, int id = -1);
 
     ~BufferNode();
 
     // Returns whether the object holds a valid metadata.
-    bool IsValid() const { return metadata_.IsValid(); }
+    bool isValid() const { return mMetadata.isValid(); }
 
     int id() const { return mId; }
 
-    size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
+    size_t userMetadataSize() const { return mMetadata.userMetadataSize(); }
 
     // Accessors of the buffer description and handle
-    const native_handle_t* buffer_handle() const { return buffer_handle_; }
-    const AHardwareBuffer_Desc& buffer_desc() const { return buffer_desc_; }
+    const native_handle_t* bufferHandle() const { return mBufferHandle; }
+    const AHardwareBuffer_Desc& bufferDesc() const { return mBufferDesc; }
 
     // Accessor of event fd.
     const BufferHubEventFd& eventFd() const { return mEventFd; }
 
-    // Accessors of metadata.
-    const BufferHubMetadata& metadata() const { return metadata_; }
+    // Accessors of mMetadata.
+    const BufferHubMetadata& metadata() const { return mMetadata; }
 
-    // Gets the current value of active_clients_bit_mask in metadata_ with
+    // Gets the current value of mActiveClientsBitMask in mMetadata with
     // std::memory_order_acquire, so that all previous releases of
-    // active_clients_bit_mask from all threads will be returned here.
-    uint32_t GetActiveClientsBitMask() const;
+    // mActiveClientsBitMask from all threads will be returned here.
+    uint32_t getActiveClientsBitMask() const;
 
-    // Find and add a new client_state_mask to active_clients_bit_mask in
-    // metadata_.
-    // Return the new client_state_mask that is added to active_clients_bit_mask.
+    // Find and add a new client state mask to mActiveClientsBitMask in
+    // mMetadata.
+    // Return the new client state mask that is added to mActiveClientsBitMask.
     // Return 0U if there are already 16 clients of the buffer.
-    uint32_t AddNewActiveClientsBitToMask();
+    uint32_t addNewActiveClientsBitToMask();
 
-    // Removes the value from active_clients_bit_mask in metadata_ with
+    // Removes the value from active_clients_bit_mask in mMetadata with
     // std::memory_order_release, so that the change will be visible to any
-    // acquire of active_clients_bit_mask_ in any threads after the succeed of
+    // acquire of mActiveClientsBitMask in any threads after the succeed of
     // this operation.
-    void RemoveClientsBitFromMask(const uint32_t& value);
+    void removeClientsBitFromMask(const uint32_t& value);
 
 private:
     // Helper method for constructors to initialize atomic metadata header
     // variables in shared memory.
-    void InitializeMetadata();
+    void initializeMetadata();
 
     // Gralloc buffer handles.
-    native_handle_t* buffer_handle_;
-    AHardwareBuffer_Desc buffer_desc_;
+    native_handle_t* mBufferHandle;
+    AHardwareBuffer_Desc mBufferDesc;
 
     // Eventfd used for signalling buffer events among the clients of the buffer.
     BufferHubEventFd mEventFd;
 
     // Metadata in shared memory.
-    BufferHubMetadata metadata_;
+    BufferHubMetadata mMetadata;
 
     // A system-unique id generated by bufferhub from 0 to std::numeric_limits<int>::max().
     // BufferNodes not created by bufferhub will have id < 0, meaning "not specified".
     // TODO(b/118891412): remove default id = -1 and update comments after pdx is no longer in use
     const int mId = -1;
 
-    // The following variables are atomic variables in metadata_ that are visible
+    // The following variables are atomic variables in mMetadata that are visible
     // to Bn object and Bp objects. Please find more info in
     // BufferHubDefs::MetadataHeader.
 
-    // buffer_state_ tracks the state of the buffer. Buffer can be in one of these
+    // mBufferState tracks the state of the buffer. Buffer can be in one of these
     // four states: gained, posted, acquired, released.
-    std::atomic<uint32_t>* buffer_state_ = nullptr;
+    std::atomic<uint32_t>* mBufferState = nullptr;
 
-    // TODO(b/112012161): add comments to fence_state_.
-    std::atomic<uint32_t>* fence_state_ = nullptr;
+    // TODO(b/112012161): add comments to mFenceState.
+    std::atomic<uint32_t>* mFenceState = nullptr;
 
-    // active_clients_bit_mask_ tracks all the bp clients of the buffer. It is the
+    // mActiveClientsBitMask tracks all the bp clients of the buffer. It is the
     // union of all client_state_mask of all bp clients.
-    std::atomic<uint32_t>* active_clients_bit_mask_ = nullptr;
+    std::atomic<uint32_t>* mActiveClientsBitMask = nullptr;
 };
 
 } // namespace implementation
diff --git a/services/bufferhub/tests/BufferNode_test.cpp b/services/bufferhub/tests/BufferNode_test.cpp
index ccb1197..2dfd4fc 100644
--- a/services/bufferhub/tests/BufferNode_test.cpp
+++ b/services/bufferhub/tests/BufferNode_test.cpp
@@ -26,80 +26,78 @@
 class BufferNodeTest : public ::testing::Test {
 protected:
     void SetUp() override {
-        buffer_node =
+        mBufferNode =
                 new BufferNode(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
-        ASSERT_TRUE(buffer_node->IsValid());
+        ASSERT_TRUE(mBufferNode->isValid());
     }
 
     void TearDown() override {
-        if (buffer_node != nullptr) {
-            delete buffer_node;
+        if (mBufferNode != nullptr) {
+            delete mBufferNode;
         }
     }
 
-    BufferNode* buffer_node = nullptr;
+    BufferNode* mBufferNode = nullptr;
 };
 
 TEST_F(BufferNodeTest, TestCreateBufferNode) {
-    EXPECT_EQ(buffer_node->user_metadata_size(), kUserMetadataSize);
+    EXPECT_EQ(mBufferNode->userMetadataSize(), kUserMetadataSize);
     // Test the handle just allocated is good (i.e. able to be imported)
     GraphicBufferMapper& mapper = GraphicBufferMapper::get();
     const native_handle_t* outHandle;
     status_t ret =
-            mapper.importBuffer(buffer_node->buffer_handle(), buffer_node->buffer_desc().width,
-                                buffer_node->buffer_desc().height,
-                                buffer_node->buffer_desc().layers,
-                                buffer_node->buffer_desc().format, buffer_node->buffer_desc().usage,
-                                buffer_node->buffer_desc().stride, &outHandle);
+            mapper.importBuffer(mBufferNode->bufferHandle(), mBufferNode->bufferDesc().width,
+                                mBufferNode->bufferDesc().height, mBufferNode->bufferDesc().layers,
+                                mBufferNode->bufferDesc().format, mBufferNode->bufferDesc().usage,
+                                mBufferNode->bufferDesc().stride, &outHandle);
     EXPECT_EQ(ret, OK);
     EXPECT_THAT(outHandle, NotNull());
 }
 
-TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_twoNewClients) {
-    uint32_t new_client_state_mask_1 = buffer_node->AddNewActiveClientsBitToMask();
-    EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), new_client_state_mask_1);
+TEST_F(BufferNodeTest, TestaddNewActiveClientsBitToMask_twoNewClients) {
+    uint32_t newClientStateMask1 = mBufferNode->addNewActiveClientsBitToMask();
+    EXPECT_EQ(mBufferNode->getActiveClientsBitMask(), newClientStateMask1);
 
     // Request and add a new client_state_mask again.
     // Active clients bit mask should be the union of the two new
     // client_state_masks.
-    uint32_t new_client_state_mask_2 = buffer_node->AddNewActiveClientsBitToMask();
-    EXPECT_EQ(buffer_node->GetActiveClientsBitMask(),
-              new_client_state_mask_1 | new_client_state_mask_2);
+    uint32_t newClientStateMask2 = mBufferNode->addNewActiveClientsBitToMask();
+    EXPECT_EQ(mBufferNode->getActiveClientsBitMask(), newClientStateMask1 | newClientStateMask2);
 }
 
-TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_32NewClients) {
-    uint32_t new_client_state_mask = 0U;
-    uint32_t current_mask = 0U;
-    uint32_t expected_mask = 0U;
+TEST_F(BufferNodeTest, TestaddNewActiveClientsBitToMask_32NewClients) {
+    uint32_t newClientStateMask = 0U;
+    uint32_t currentMask = 0U;
+    uint32_t expectedMask = 0U;
 
     for (int i = 0; i < BufferHubDefs::kMaxNumberOfClients; ++i) {
-        new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
-        EXPECT_NE(new_client_state_mask, 0U);
-        EXPECT_FALSE(new_client_state_mask & current_mask);
-        expected_mask = current_mask | new_client_state_mask;
-        current_mask = buffer_node->GetActiveClientsBitMask();
-        EXPECT_EQ(current_mask, expected_mask);
+        newClientStateMask = mBufferNode->addNewActiveClientsBitToMask();
+        EXPECT_NE(newClientStateMask, 0U);
+        EXPECT_FALSE(newClientStateMask & currentMask);
+        expectedMask = currentMask | newClientStateMask;
+        currentMask = mBufferNode->getActiveClientsBitMask();
+        EXPECT_EQ(currentMask, expectedMask);
     }
 
     // Method should fail upon requesting for more than maximum allowable clients.
-    new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
-    EXPECT_EQ(new_client_state_mask, 0U);
+    newClientStateMask = mBufferNode->addNewActiveClientsBitToMask();
+    EXPECT_EQ(newClientStateMask, 0U);
     EXPECT_EQ(errno, E2BIG);
 }
 
 TEST_F(BufferNodeTest, TestRemoveActiveClientsBitFromMask) {
-    buffer_node->AddNewActiveClientsBitToMask();
-    uint32_t current_mask = buffer_node->GetActiveClientsBitMask();
-    uint32_t new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
-    EXPECT_NE(buffer_node->GetActiveClientsBitMask(), current_mask);
+    mBufferNode->addNewActiveClientsBitToMask();
+    uint32_t currentMask = mBufferNode->getActiveClientsBitMask();
+    uint32_t newClientStateMask = mBufferNode->addNewActiveClientsBitToMask();
+    EXPECT_NE(mBufferNode->getActiveClientsBitMask(), currentMask);
 
-    buffer_node->RemoveClientsBitFromMask(new_client_state_mask);
-    EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
+    mBufferNode->removeClientsBitFromMask(newClientStateMask);
+    EXPECT_EQ(mBufferNode->getActiveClientsBitMask(), currentMask);
 
     // Remove the test_mask again to the active client bit mask should not modify
     // the value of active clients bit mask.
-    buffer_node->RemoveClientsBitFromMask(new_client_state_mask);
-    EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
+    mBufferNode->removeClientsBitFromMask(newClientStateMask);
+    EXPECT_EQ(mBufferNode->getActiveClientsBitMask(), currentMask);
 }
 
 } // namespace
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 47bed65..e21d8e7 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -30,6 +30,8 @@
     ],
     shared_libs: [
         "libbinder",
+        "libcutils",
+        "libgraphicsenv",
         "liblog",
         "libutils",
         "libvulkan",
@@ -59,6 +61,7 @@
     ],
     shared_libs: [
         "libbinder",
+        "libcutils",
         "liblog",
         "libutils",
     ],
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 150896c..ed56c49 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -14,48 +14,19 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include "GpuService.h"
 
 #include <binder/IResultReceiver.h>
 #include <binder/Parcel.h>
 #include <utils/String8.h>
+#include <utils/Trace.h>
+
 #include <vkjson.h>
 
 namespace android {
 
-class BpGpuService : public BpInterface<IGpuService> {
-public:
-    explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
-};
-
-IMPLEMENT_META_INTERFACE(GpuService, "android.ui.IGpuService");
-
-status_t BnGpuService::onTransact(uint32_t code, const Parcel& data,
-        Parcel* reply, uint32_t flags) {
-    status_t status;
-    switch (code) {
-    case SHELL_COMMAND_TRANSACTION: {
-        int in = data.readFileDescriptor();
-        int out = data.readFileDescriptor();
-        int err = data.readFileDescriptor();
-        std::vector<String16> args;
-        data.readString16Vector(&args);
-        sp<IBinder> unusedCallback;
-        sp<IResultReceiver> resultReceiver;
-        if ((status = data.readNullableStrongBinder(&unusedCallback)) != OK)
-            return status;
-        if ((status = data.readNullableStrongBinder(&resultReceiver)) != OK)
-            return status;
-        status = shellCommand(in, out, err, args);
-        if (resultReceiver != nullptr)
-            resultReceiver->send(status);
-        return OK;
-    }
-
-    default:
-        return BBinder::onTransact(code, data, reply, flags);
-    }
-}
 
 namespace {
     status_t cmd_help(int out);
@@ -66,9 +37,31 @@
 
 GpuService::GpuService() = default;
 
-status_t GpuService::shellCommand(int /*in*/, int out, int err,
-                                  std::vector<String16>& args) {
-    ALOGV("GpuService::shellCommand");
+void GpuService::setGpuStats(const std::string& driverPackageName,
+                             const std::string& driverVersionName, uint64_t driverVersionCode,
+                             int64_t driverBuildTime, const std::string& appPackageName,
+                             GraphicsEnv::Driver driver, bool isDriverLoaded,
+                             int64_t driverLoadingTime) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mStateLock);
+    ALOGV("Received:\n"
+          "\tdriverPackageName[%s]\n"
+          "\tdriverVersionName[%s]\n"
+          "\tdriverVersionCode[%" PRIu64 "]\n"
+          "\tdriverBuildTime[%" PRId64 "]\n"
+          "\tappPackageName[%s]\n"
+          "\tdriver[%d]\n"
+          "\tisDriverLoaded[%d]\n"
+          "\tdriverLoadingTime[%" PRId64 "]",
+          driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
+          appPackageName.c_str(), static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
+}
+
+status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) {
+    ATRACE_CALL();
+
+    ALOGV("shellCommand");
     for (size_t i = 0, n = args.size(); i < n; i++)
         ALOGV("  arg[%zu]: '%s'", i, String8(args[i]).string());
 
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index e2b396e..389e695 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -17,31 +17,15 @@
 #ifndef ANDROID_GPUSERVICE_H
 #define ANDROID_GPUSERVICE_H
 
-#include <vector>
-
 #include <binder/IInterface.h>
 #include <cutils/compiler.h>
+#include <graphicsenv/IGpuService.h>
+
+#include <mutex>
+#include <vector>
 
 namespace android {
 
-/*
- * This class defines the Binder IPC interface for GPU-related queries and
- * control.
- */
-class IGpuService : public IInterface {
-public:
-    DECLARE_META_INTERFACE(GpuService);
-};
-
-class BnGpuService: public BnInterface<IGpuService> {
-protected:
-    virtual status_t shellCommand(int in, int out, int err,
-                                  std::vector<String16>& args) = 0;
-
-    status_t onTransact(uint32_t code, const Parcel& data,
-            Parcel* reply, uint32_t flags = 0) override;
-};
-
 class GpuService : public BnGpuService {
 public:
     static const char* const SERVICE_NAME ANDROID_API;
@@ -49,8 +33,17 @@
     GpuService() ANDROID_API;
 
 protected:
-    status_t shellCommand(int in, int out, int err,
-                          std::vector<String16>& args) override;
+    status_t shellCommand(int in, int out, int err, std::vector<String16>& args) override;
+
+private:
+    // IGpuService interface
+    void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
+                     uint64_t driverVersionCode, int64_t driverBuildTime,
+                     const std::string& appPackageName, GraphicsEnv::Driver driver,
+                     bool isDriverLoaded, int64_t driverLoadingTime);
+
+    // GpuStats access must be protected by mStateLock
+    std::mutex mStateLock;
 };
 
 } // namespace android
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index f73d498..63e759c 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -12,8 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+cc_defaults {
+    name: "inputflinger_defaults",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wthread-safety",
+    ],
+}
+
 cc_library_shared {
     name: "libinputflinger",
+    defaults: ["inputflinger_defaults"],
 
     srcs: [
         "InputClassifier.cpp",
@@ -23,10 +35,10 @@
 
     shared_libs: [
         "android.hardware.input.classifier@1.0",
+        "libbase",
         "libinputflinger_base",
         "libinputreporter",
         "libinputreader",
-        "libbase",
         "libbinder",
         "libcutils",
         "libhidlbase",
@@ -38,12 +50,6 @@
     ],
 
     cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-Wno-unused-parameter",
-        // TODO(b/123097103): annotate InputDispatcher and uncomment the following line
-        //"-Wthread-safety",
         // TODO(b/23084678): Move inputflinger to its own process and mark it hidden
         //-fvisibility=hidden
     ],
@@ -55,15 +61,14 @@
 
 }
 
-
 cc_library_headers {
-   name: "libinputflinger_headers",
-
-   export_include_dirs: ["include"],
+    name: "libinputflinger_headers",
+    export_include_dirs: ["include"],
 }
 
 cc_library_shared {
     name: "libinputreader",
+    defaults: ["inputflinger_defaults"],
 
     srcs: [
         "EventHub.cpp",
@@ -73,17 +78,16 @@
     ],
 
     shared_libs: [
-        "libinputflinger_base",
         "libbase",
+        "libinputflinger_base",
         "libcrypto",
         "libcutils",
         "libinput",
         "liblog",
-        "libutils",
         "libui",
+        "libutils",
         "libhardware_legacy",
         "libstatslog",
-        "libutils",
     ],
 
     header_libs: [
@@ -93,17 +97,11 @@
     export_header_lib_headers: [
         "libinputflinger_headers",
     ],
-
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-Wno-unused-parameter",
-    ],
 }
 
 cc_library_shared {
     name: "libinputflinger_base",
+    defaults: ["inputflinger_defaults"],
 
     srcs: [
         "InputListener.cpp",
@@ -124,24 +122,17 @@
     export_header_lib_headers: [
         "libinputflinger_headers",
     ],
-
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-Wno-unused-parameter",
-    ],
 }
 
 cc_library_shared {
     name: "libinputreporter",
+    defaults: ["inputflinger_defaults"],
 
     srcs: [
         "InputReporter.cpp",
     ],
 
     shared_libs: [
-        "libbase",
         "liblog",
         "libutils",
     ],
@@ -153,13 +144,6 @@
     export_header_lib_headers: [
         "libinputflinger_headers",
     ],
-
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-Wno-unused-parameter",
-    ],
 }
 
 subdirs = [
diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h
index b892120..4b16027 100644
--- a/services/inputflinger/BlockingQueue.h
+++ b/services/inputflinger/BlockingQueue.h
@@ -17,6 +17,7 @@
 #ifndef _UI_INPUT_BLOCKING_QUEUE_H
 #define _UI_INPUT_BLOCKING_QUEUE_H
 
+#include "android-base/thread_annotations.h"
 #include <condition_variable>
 #include <mutex>
 #include <vector>
@@ -43,10 +44,14 @@
      */
     T pop() {
         std::unique_lock<std::mutex> lock(mLock);
-        mHasElements.wait(lock, [this]{ return !this->mQueue.empty(); });
+        android::base::ScopedLockAssertion assumeLock(mLock);
+        mHasElements.wait(lock, [this]{
+                android::base::ScopedLockAssertion assumeLock(mLock);
+                return !this->mQueue.empty();
+        });
         T t = std::move(mQueue.front());
         mQueue.erase(mQueue.begin());
-        return std::move(t);
+        return t;
     };
 
     /**
@@ -56,17 +61,19 @@
      * Return false if the queue is full.
      */
     bool push(T&& t) {
-        std::unique_lock<std::mutex> lock(mLock);
-        if (mQueue.size() == mCapacity) {
-            return false;
+        {
+            std::scoped_lock lock(mLock);
+            if (mQueue.size() == mCapacity) {
+                return false;
+            }
+            mQueue.push_back(std::move(t));
         }
-        mQueue.push_back(std::move(t));
         mHasElements.notify_one();
         return true;
     };
 
     void erase(const std::function<bool(const T&)>& lambda) {
-        std::unique_lock<std::mutex> lock(mLock);
+        std::scoped_lock lock(mLock);
         mQueue.erase(std::remove_if(mQueue.begin(), mQueue.end(),
                 [&lambda](const T& t) { return lambda(t); }), mQueue.end());
     }
@@ -80,8 +87,18 @@
         mQueue.clear();
     };
 
+    /**
+     * How many elements are currently stored in the queue.
+     * Primary used for debugging.
+     * Does not block.
+     */
+    size_t size() {
+        std::scoped_lock lock(mLock);
+        return mQueue.size();
+    }
+
 private:
-    size_t mCapacity;
+    const size_t mCapacity;
     /**
      * Used to signal that mQueue is non-empty.
      */
@@ -90,7 +107,7 @@
      * Lock for accessing and waiting on elements.
      */
     std::mutex mLock;
-    std::vector<T> mQueue; //GUARDED_BY(mLock)
+    std::vector<T> mQueue GUARDED_BY(mLock);
 };
 
 
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index cf9d3c7..4da1473 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -202,7 +202,6 @@
 EventHub::Device::~Device() {
     close();
     delete configuration;
-    delete virtualKeyMap;
 }
 
 void EventHub::Device::close() {
@@ -763,7 +762,7 @@
 }
 
 EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
-    if (deviceId == BUILT_IN_KEYBOARD_ID) {
+    if (deviceId == ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID) {
         deviceId = mBuiltInKeyboardId;
     }
     ssize_t index = mDevices.indexOfKey(deviceId);
@@ -835,7 +834,8 @@
                  device->id, device->path.c_str());
             mClosingDevices = device->next;
             event->when = now;
-            event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
+            event->deviceId = (device->id == mBuiltInKeyboardId) ?
+                    ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID : device->id;
             event->type = DEVICE_REMOVED;
             event += 1;
             delete device;
@@ -1081,7 +1081,7 @@
             ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
         }
     }
-    if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
+    if (mDevices.indexOfKey(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) < 0) {
         createVirtualKeyboardLocked();
     }
 }
@@ -1363,8 +1363,8 @@
     if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
         // Load the virtual keys for the touch screen, if any.
         // We do this now so that we can make sure to load the keymap if necessary.
-        status_t status = loadVirtualKeyMapLocked(device);
-        if (!status) {
+        bool success = loadVirtualKeyMapLocked(device);
+        if (success) {
             device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
         }
     }
@@ -1580,7 +1580,8 @@
     identifier.uniqueId = "<virtual>";
     assignDescriptorLocked(identifier);
 
-    Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, "<virtual>", identifier);
+    Device* device = new Device(-1, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, "<virtual>",
+            identifier);
     device->classes = INPUT_DEVICE_CLASS_KEYBOARD
             | INPUT_DEVICE_CLASS_ALPHAKEY
             | INPUT_DEVICE_CLASS_DPAD
@@ -1612,15 +1613,16 @@
     }
 }
 
-status_t EventHub::loadVirtualKeyMapLocked(Device* device) {
+bool EventHub::loadVirtualKeyMapLocked(Device* device) {
     // The virtual key map is supplied by the kernel as a system board property file.
     std::string path;
     path += "/sys/board_properties/virtualkeys.";
-    path += device->identifier.name;
+    path += device->identifier.getCanonicalName();
     if (access(path.c_str(), R_OK)) {
-        return NAME_NOT_FOUND;
+        return false;
     }
-    return VirtualKeyMap::load(path, &device->virtualKeyMap);
+    device->virtualKeyMap = VirtualKeyMap::load(path);
+    return device->virtualKeyMap != nullptr;
 }
 
 status_t EventHub::loadKeyMapLocked(Device* device) {
diff --git a/services/inputflinger/include/EventHub.h b/services/inputflinger/EventHub.h
similarity index 98%
rename from services/inputflinger/include/EventHub.h
rename to services/inputflinger/EventHub.h
index 295aca8..44f7b37 100644
--- a/services/inputflinger/include/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -46,13 +46,6 @@
 
 namespace android {
 
-enum {
-    // Device id of a special "virtual" keyboard that is always present.
-    VIRTUAL_KEYBOARD_ID = -1,
-    // Device id of the "built-in" keyboard if there is one.
-    BUILT_IN_KEYBOARD_ID = 0,
-};
-
 /*
  * A raw event as retrieved from the EventHub.
  */
@@ -352,7 +345,7 @@
 
         std::string configurationFile;
         PropertyMap* configuration;
-        VirtualKeyMap* virtualKeyMap;
+        std::unique_ptr<VirtualKeyMap> virtualKeyMap;
         KeyMap keyMap;
 
         sp<KeyCharacterMap> overlayKeyMap;
@@ -423,7 +416,7 @@
     bool hasKeycodeLocked(Device* device, int keycode) const;
 
     void loadConfigurationLocked(Device* device);
-    status_t loadVirtualKeyMapLocked(Device* device);
+    bool loadVirtualKeyMapLocked(Device* device);
     status_t loadKeyMapLocked(Device* device);
 
     bool isExternalDeviceLocked(Device* device);
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 7ade0d4..3905ed0 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -19,6 +19,7 @@
 #include "InputClassifier.h"
 
 #include <algorithm>
+#include <android-base/stringprintf.h>
 #include <cmath>
 #include <inttypes.h>
 #include <log/log.h>
@@ -26,9 +27,17 @@
     #include <pthread.h>
 #endif
 #include <server_configurable_flags/get_flags.h>
+#include <unordered_set>
 
 #include <android/hardware/input/classifier/1.0/IInputClassifier.h>
 
+#define INDENT1 "  "
+#define INDENT2 "    "
+#define INDENT3 "      "
+#define INDENT4 "        "
+#define INDENT5 "          "
+
+using android::base::StringPrintf;
 using android::hardware::hidl_bitfield;
 using android::hardware::hidl_vec;
 using namespace android::hardware::input;
@@ -646,6 +655,30 @@
     mEvents.push(std::make_unique<NotifyDeviceResetArgs>(args));
 }
 
+void MotionClassifier::dump(std::string& dump) {
+    std::scoped_lock lock(mLock);
+    std::string serviceStatus = mService->ping().isOk() ? "running" : " not responding";
+    dump += StringPrintf(INDENT2 "mService status: %s\n", serviceStatus.c_str());
+    dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n",
+            mEvents.size(), MAX_EVENTS);
+    dump += INDENT2 "mClassifications, mLastDownTimes:\n";
+    dump += INDENT3 "Device Id\tClassification\tLast down time";
+    // Combine mClassifications and mLastDownTimes into a single table.
+    // Create a superset of device ids.
+    std::unordered_set<int32_t> deviceIds;
+    std::for_each(mClassifications.begin(), mClassifications.end(),
+            [&deviceIds](auto pair){ deviceIds.insert(pair.first); });
+    std::for_each(mLastDownTimes.begin(), mLastDownTimes.end(),
+            [&deviceIds](auto pair){ deviceIds.insert(pair.first); });
+    for(int32_t deviceId : deviceIds) {
+        const MotionClassification classification =
+                getValueForKey(mClassifications, deviceId, MotionClassification::NONE);
+        const nsecs_t downTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0));
+        dump += StringPrintf("\n" INDENT4 "%" PRId32 "\t%s\t%" PRId64,
+                deviceId, motionClassificationToString(classification), downTime);
+    }
+}
+
 // --- InputClassifier ---
 
 InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener) :
@@ -672,13 +705,12 @@
 }
 
 void InputClassifier::notifyMotion(const NotifyMotionArgs* args) {
+    NotifyMotionArgs copyArgs = NotifyMotionArgs(*args);
     if (mMotionClassifier && isTouchEvent(*args)) {
         // We only cover touch events, for now.
-        NotifyMotionArgs newArgs = NotifyMotionArgs(*args);
-        newArgs.classification = mMotionClassifier->classify(newArgs);
-        args = &newArgs;
+        copyArgs.classification = mMotionClassifier->classify(copyArgs);
     }
-    mListener->notifyMotion(args);
+    mListener->notifyMotion(&copyArgs);
 }
 
 void InputClassifier::notifySwitch(const NotifySwitchArgs* args) {
@@ -694,4 +726,16 @@
     mListener->notifyDeviceReset(args);
 }
 
+void InputClassifier::dump(std::string& dump) {
+    dump += "Input Classifier State:\n";
+
+    dump += INDENT1 "Motion Classifier:\n";
+    if (mMotionClassifier) {
+        mMotionClassifier->dump(dump);
+    } else {
+        dump += INDENT2 "<nullptr>";
+    }
+    dump += "\n";
+}
+
 } // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index cb46494..b97357d 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -17,6 +17,7 @@
 #ifndef _UI_INPUT_CLASSIFIER_H
 #define _UI_INPUT_CLASSIFIER_H
 
+#include <android-base/thread_annotations.h>
 #include <utils/RefBase.h>
 #include <unordered_map>
 #include <thread>
@@ -70,6 +71,11 @@
     virtual MotionClassification classify(const NotifyMotionArgs& args) = 0;
     virtual void reset() = 0;
     virtual void reset(const NotifyDeviceResetArgs& args) = 0;
+
+    /**
+     * Dump the state of the motion classifier
+     */
+    virtual void dump(std::string& dump) = 0;
 };
 
 /**
@@ -77,6 +83,12 @@
  * Provides classification to events.
  */
 class InputClassifierInterface : public virtual RefBase, public InputListenerInterface {
+public:
+    /**
+     * Dump the state of the input classifier.
+     * This method may be called on any thread (usually by the input manager).
+     */
+    virtual void dump(std::string& dump) = 0;
 protected:
     InputClassifierInterface() { }
     virtual ~InputClassifierInterface() { }
@@ -110,6 +122,8 @@
     virtual void reset() override;
     virtual void reset(const NotifyDeviceResetArgs& args) override;
 
+    virtual void dump(std::string& dump) override;
+
 private:
     // The events that need to be sent to the HAL.
     BlockingQueue<ClassifierEvent> mEvents;
@@ -138,7 +152,7 @@
      * getClassification / setClassification methods.
      */
     std::unordered_map<int32_t /*deviceId*/, MotionClassification>
-            mClassifications; //GUARDED_BY(mLock);
+            mClassifications GUARDED_BY(mLock);
     /**
      * Set the current classification for a given device.
      */
@@ -148,7 +162,7 @@
      */
     MotionClassification getClassification(int32_t deviceId);
     void updateClassification(int32_t deviceId, nsecs_t eventTime,
-        MotionClassification classification);
+            MotionClassification classification);
     /**
      * Clear all current classifications
      */
@@ -159,8 +173,8 @@
      *
      * Accessed indirectly by both InputClassifier thread and the thread that receives notifyMotion.
      */
-    std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/>
-            mLastDownTimes; //GUARDED_BY(mLock);
+    std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/> mLastDownTimes GUARDED_BY(mLock);
+
     void updateLastDownTime(int32_t deviceId, nsecs_t downTime);
 
     /**
@@ -186,6 +200,8 @@
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
 
+    virtual void dump(std::string& dump) override;
+
 private:
     std::unique_ptr<MotionClassifierInterface> mMotionClassifier = nullptr;
     // The next stage to pass input events to
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 9702fb2..d288736 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -401,7 +401,7 @@
     case EventEntry::TYPE_KEY: {
         KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
         if (isAppSwitchDue) {
-            if (isAppSwitchKeyEventLocked(typedEntry)) {
+            if (isAppSwitchKeyEvent(typedEntry)) {
                 resetPendingAppSwitchLocked(true);
                 isAppSwitchDue = false;
             } else if (dropReason == DROP_REASON_NOT_DROPPED) {
@@ -409,7 +409,7 @@
             }
         }
         if (dropReason == DROP_REASON_NOT_DROPPED
-                && isStaleEventLocked(currentTime, typedEntry)) {
+                && isStaleEvent(currentTime, typedEntry)) {
             dropReason = DROP_REASON_STALE;
         }
         if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
@@ -425,7 +425,7 @@
             dropReason = DROP_REASON_APP_SWITCH;
         }
         if (dropReason == DROP_REASON_NOT_DROPPED
-                && isStaleEventLocked(currentTime, typedEntry)) {
+                && isStaleEvent(currentTime, typedEntry)) {
             dropReason = DROP_REASON_STALE;
         }
         if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
@@ -463,7 +463,7 @@
         // If the application takes too long to catch up then we drop all events preceding
         // the app switch key.
         KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
-        if (isAppSwitchKeyEventLocked(keyEntry)) {
+        if (isAppSwitchKeyEvent(keyEntry)) {
             if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
                 mAppSwitchSawKeyDown = true;
             } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
@@ -615,13 +615,13 @@
     }
 }
 
-bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) {
+static bool isAppSwitchKeyCode(int32_t keyCode) {
     return keyCode == AKEYCODE_HOME
             || keyCode == AKEYCODE_ENDCALL
             || keyCode == AKEYCODE_APP_SWITCH;
 }
 
-bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) {
+bool InputDispatcher::isAppSwitchKeyEvent(KeyEntry* keyEntry) {
     return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED)
             && isAppSwitchKeyCode(keyEntry->keyCode)
             && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED)
@@ -644,7 +644,7 @@
 #endif
 }
 
-bool InputDispatcher::isStaleEventLocked(nsecs_t currentTime, EventEntry* entry) {
+bool InputDispatcher::isStaleEvent(nsecs_t currentTime, EventEntry* entry) {
     return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT;
 }
 
@@ -756,7 +756,7 @@
 
     // Enqueue a command to run outside the lock to tell the policy that the configuration changed.
     CommandEntry* commandEntry = postCommandLocked(
-            & InputDispatcher::doNotifyConfigurationChangedInterruptible);
+            & InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
     commandEntry->eventTime = entry->eventTime;
     return true;
 }
@@ -811,7 +811,7 @@
 
         entry->dispatchInProgress = true;
 
-        logOutboundKeyDetailsLocked("dispatchKey - ", entry);
+        logOutboundKeyDetails("dispatchKey - ", entry);
     }
 
     // Handle case where the policy asked us to try again later last time.
@@ -878,7 +878,7 @@
     return true;
 }
 
-void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) {
+void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
     ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", "
             "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
@@ -896,7 +896,7 @@
     if (! entry->dispatchInProgress) {
         entry->dispatchInProgress = true;
 
-        logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
+        logOutboundMotionDetails("dispatchMotion - ", entry);
     }
 
     // Clean up if dropping the event.
@@ -968,7 +968,7 @@
 }
 
 
-void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
+void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
     ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
             ", policyFlags=0x%x, "
@@ -1049,7 +1049,7 @@
         if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
 #if DEBUG_FOCUS
             ALOGD("Waiting for application to become ready for input: %s.  Reason: %s",
-                    getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str(),
+                    getApplicationWindowLabel(applicationHandle, windowHandle).c_str(),
                     reason);
 #endif
             nsecs_t timeout;
@@ -1233,8 +1233,7 @@
 Failed:
 Unresponsive:
     nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
-    updateDispatchStatisticsLocked(currentTime, entry,
-            injectionResult, timeSpentWaitingForApplication);
+    updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication);
 #if DEBUG_FOCUS
     ALOGD("findFocusedWindow finished: injectionResult=%d, "
             "timeSpentWaitingForApplication=%0.1fms",
@@ -1654,8 +1653,7 @@
     mTempTouchState.reset();
 
     nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
-    updateDispatchStatisticsLocked(currentTime, entry,
-            injectionResult, timeSpentWaitingForApplication);
+    updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication);
 #if DEBUG_FOCUS
     ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, "
             "timeSpentWaitingForApplication=%0.1fms",
@@ -1857,7 +1855,7 @@
     return "";
 }
 
-std::string InputDispatcher::getApplicationWindowLabelLocked(
+std::string InputDispatcher::getApplicationWindowLabel(
         const sp<InputApplicationHandle>& applicationHandle,
         const sp<InputWindowHandle>& windowHandle) {
     if (applicationHandle != nullptr) {
@@ -1956,7 +1954,7 @@
 #if DEBUG_FOCUS
             ALOGD("channel '%s' ~ Split motion event.",
                     connection->getInputChannelName().c_str());
-            logOutboundMotionDetailsLocked("  ", splitMotionEntry);
+            logOutboundMotionDetails("  ", splitMotionEntry);
 #endif
             enqueueDispatchEntriesLocked(currentTime, connection,
                     splitMotionEntry, inputTarget);
@@ -2076,12 +2074,12 @@
 
     // Remember that we are waiting for this dispatch to complete.
     if (dispatchEntry->hasForegroundTarget()) {
-        incrementPendingForegroundDispatchesLocked(eventEntry);
+        incrementPendingForegroundDispatches(eventEntry);
     }
 
     // Enqueue the dispatch entry.
     connection->outboundQueue.enqueueAtTail(dispatchEntry);
-    traceOutboundQueueLengthLocked(connection);
+    traceOutboundQueueLength(connection);
 }
 
 void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -2196,9 +2194,9 @@
 
         // Re-enqueue the event on the wait queue.
         connection->outboundQueue.dequeue(dispatchEntry);
-        traceOutboundQueueLengthLocked(connection);
+        traceOutboundQueueLength(connection);
         connection->waitQueue.enqueueAtTail(dispatchEntry);
-        traceWaitQueueLengthLocked(connection);
+        traceWaitQueueLength(connection);
     }
 }
 
@@ -2229,9 +2227,9 @@
 
     // Clear the dispatch queues.
     drainDispatchQueueLocked(&connection->outboundQueue);
-    traceOutboundQueueLengthLocked(connection);
+    traceOutboundQueueLength(connection);
     drainDispatchQueueLocked(&connection->waitQueue);
-    traceWaitQueueLengthLocked(connection);
+    traceWaitQueueLength(connection);
 
     // The connection appears to be unrecoverably broken.
     // Ignore already broken or zombie connections.
@@ -2323,7 +2321,7 @@
     } // release lock
 }
 
-void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
+void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked (
         const CancelationOptions& options) {
     for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
         synthesizeCancelationEventsForConnectionLocked(
@@ -2331,7 +2329,7 @@
     }
 }
 
-void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked(
+void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked (
         const CancelationOptions& options) {
     for (auto& it : mMonitoringChannelsByDisplay) {
         const Vector<sp<InputChannel>>& monitoringChannels = it.second;
@@ -2374,11 +2372,11 @@
             EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i);
             switch (cancelationEventEntry->type) {
             case EventEntry::TYPE_KEY:
-                logOutboundKeyDetailsLocked("cancel - ",
+                logOutboundKeyDetails("cancel - ",
                         static_cast<KeyEntry*>(cancelationEventEntry));
                 break;
             case EventEntry::TYPE_MOTION:
-                logOutboundMotionDetailsLocked("cancel - ",
+                logOutboundMotionDetails("cancel - ",
                         static_cast<MotionEntry*>(cancelationEventEntry));
                 break;
             }
@@ -2673,7 +2671,7 @@
     policyFlags |= POLICY_FLAG_TRUSTED;
 
     android::base::Timer t;
-    mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);
+    mPolicy->interceptMotionBeforeQueueing(args->displayId, args->eventTime, /*byref*/ policyFlags);
     if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
         ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
                 std::to_string(t.duration().count()).c_str());
@@ -2821,6 +2819,7 @@
         size_t pointerCount = motionEvent->getPointerCount();
         const PointerProperties* pointerProperties = motionEvent->getPointerProperties();
         int32_t actionButton = motionEvent->getActionButton();
+        int32_t displayId = motionEvent->getDisplayId();
         if (! validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) {
             return INPUT_EVENT_INJECTION_FAILED;
         }
@@ -2828,7 +2827,7 @@
         if (!(policyFlags & POLICY_FLAG_FILTERED)) {
             nsecs_t eventTime = motionEvent->getEventTime();
             android::base::Timer t;
-            mPolicy->interceptMotionBeforeQueueing(eventTime, /*byref*/ policyFlags);
+            mPolicy->interceptMotionBeforeQueueing(displayId, eventTime, /*byref*/ policyFlags);
             if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
                 ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
                         std::to_string(t.duration().count()).c_str());
@@ -2993,7 +2992,7 @@
     }
 }
 
-void InputDispatcher::incrementPendingForegroundDispatchesLocked(EventEntry* entry) {
+void InputDispatcher::incrementPendingForegroundDispatches(EventEntry* entry) {
     InjectionState* injectionState = entry->injectionState;
     if (injectionState) {
         injectionState->pendingForegroundDispatches += 1;
@@ -3013,7 +3012,7 @@
 
 Vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(int32_t displayId) const {
     std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>>::const_iterator it =
-        mWindowHandlesByDisplay.find(displayId);
+            mWindowHandlesByDisplay.find(displayId);
     if(it != mWindowHandlesByDisplay.end()) {
         return it->second;
     }
@@ -3037,8 +3036,7 @@
     return nullptr;
 }
 
-bool InputDispatcher::hasWindowHandleLocked(
-        const sp<InputWindowHandle>& windowHandle) const {
+bool InputDispatcher::hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const {
     for (auto& it : mWindowHandlesByDisplay) {
         const Vector<sp<InputWindowHandle>> windowHandles = it.second;
         size_t numWindows = windowHandles.size();
@@ -3074,7 +3072,7 @@
  * For removed handle, check if need to send a cancel event if already in touch.
  */
 void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& inputWindowHandles,
-        int32_t displayId) {
+        int32_t displayId, const sp<ISetInputWindowsListener>& setInputWindowsListener) {
 #if DEBUG_FOCUS
     ALOGD("setInputWindows displayId=%" PRId32, displayId);
 #endif
@@ -3224,6 +3222,10 @@
 
     // Wake up poll loop since it may need to make new input dispatching choices.
     mLooper->wake();
+
+    if (setInputWindowsListener) {
+        setInputWindowsListener->onSetInputWindowsFinished();
+    }
 }
 
 void InputDispatcher::setFocusedApplication(
@@ -3883,7 +3885,7 @@
     float waitDuration = (currentTime - waitStartTime) * 0.000001f;
     ALOGI("Application is not responding: %s.  "
             "It has been %0.1fms since event, %0.1fms since wait started.  Reason: %s",
-            getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str(),
+            getApplicationWindowLabel(applicationHandle, windowHandle).c_str(),
             dispatchLatency, waitDuration, reason);
 
     // Capture a record of the InputDispatcher state at the time of the ANR.
@@ -3896,7 +3898,7 @@
     mLastANRState += INDENT "ANR:\n";
     mLastANRState += StringPrintf(INDENT2 "Time: %s\n", timestr);
     mLastANRState += StringPrintf(INDENT2 "Window: %s\n",
-            getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str());
+            getApplicationWindowLabel(applicationHandle, windowHandle).c_str());
     mLastANRState += StringPrintf(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency);
     mLastANRState += StringPrintf(INDENT2 "WaitDuration: %0.1fms\n", waitDuration);
     mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason);
@@ -3910,7 +3912,7 @@
     commandEntry->reason = reason;
 }
 
-void InputDispatcher::doNotifyConfigurationChangedInterruptible(
+void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible (
         CommandEntry* commandEntry) {
     mLock.unlock();
 
@@ -4026,10 +4028,10 @@
         // a few things.
         if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
             connection->waitQueue.dequeue(dispatchEntry);
-            traceWaitQueueLengthLocked(connection);
+            traceWaitQueueLength(connection);
             if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
                 connection->outboundQueue.enqueueAtHead(dispatchEntry);
-                traceOutboundQueueLengthLocked(connection);
+                traceOutboundQueueLength(connection);
             } else {
                 releaseDispatchEntryLocked(dispatchEntry);
             }
@@ -4241,7 +4243,7 @@
             entry->downTime, entry->eventTime);
 }
 
-void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
+void InputDispatcher::updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry,
         int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) {
     // TODO Write some statistics about how long we spend waiting.
 }
@@ -4252,7 +4254,7 @@
     }
 }
 
-void InputDispatcher::traceOutboundQueueLengthLocked(const sp<Connection>& connection) {
+void InputDispatcher::traceOutboundQueueLength(const sp<Connection>& connection) {
     if (ATRACE_ENABLED()) {
         char counterName[40];
         snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName().c_str());
@@ -4260,7 +4262,7 @@
     }
 }
 
-void InputDispatcher::traceWaitQueueLengthLocked(const sp<Connection>& connection) {
+void InputDispatcher::traceWaitQueueLength(const sp<Connection>& connection) {
     if (ATRACE_ENABLED()) {
         char counterName[40];
         snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName().c_str());
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 2d8df5c..9d8919b 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -21,6 +21,7 @@
 #include <input/InputApplication.h>
 #include <input/InputTransport.h>
 #include <input/InputWindow.h>
+#include <input/ISetInputWindowsListener.h>
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
 #include <utils/threads.h>
@@ -39,7 +40,6 @@
 #include "InputListener.h"
 #include "InputReporterInterface.h"
 
-
 namespace android {
 
 /*
@@ -245,7 +245,8 @@
      * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
      * should be dispatched to applications.
      */
-    virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0;
+    virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
+            uint32_t& policyFlags) = 0;
 
     /* Allows the policy a chance to intercept a key before dispatching. */
     virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token,
@@ -314,7 +315,8 @@
      * This method may be called on any thread (usually by the input manager).
      */
     virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
-            int32_t displayId) = 0;
+            int32_t displayId,
+            const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) = 0;
 
     /* Sets the focused application on the given display.
      *
@@ -405,7 +407,8 @@
             uint32_t policyFlags);
 
     virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
-            int32_t displayId);
+            int32_t displayId,
+            const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr);
     virtual void setFocusedApplication(int32_t displayId,
             const sp<InputApplicationHandle>& inputApplicationHandle);
     virtual void setFocusedDisplay(int32_t displayId);
@@ -887,57 +890,58 @@
 
     sp<Looper> mLooper;
 
-    EventEntry* mPendingEvent;
-    Queue<EventEntry> mInboundQueue;
-    Queue<EventEntry> mRecentQueue;
-    Queue<CommandEntry> mCommandQueue;
+    EventEntry* mPendingEvent GUARDED_BY(mLock);
+    Queue<EventEntry> mInboundQueue GUARDED_BY(mLock);
+    Queue<EventEntry> mRecentQueue GUARDED_BY(mLock);
+    Queue<CommandEntry> mCommandQueue GUARDED_BY(mLock);
 
-    DropReason mLastDropReason;
+    DropReason mLastDropReason GUARDED_BY(mLock);
 
-    void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
+    void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) REQUIRES(mLock);
 
     // Enqueues an inbound event.  Returns true if mLooper->wake() should be called.
-    bool enqueueInboundEventLocked(EventEntry* entry);
+    bool enqueueInboundEventLocked(EventEntry* entry) REQUIRES(mLock);
 
     // Cleans up input state when dropping an inbound event.
-    void dropInboundEventLocked(EventEntry* entry, DropReason dropReason);
+    void dropInboundEventLocked(EventEntry* entry, DropReason dropReason) REQUIRES(mLock);
 
     // Adds an event to a queue of recent events for debugging purposes.
-    void addRecentEventLocked(EventEntry* entry);
+    void addRecentEventLocked(EventEntry* entry) REQUIRES(mLock);
 
     // App switch latency optimization.
-    bool mAppSwitchSawKeyDown;
-    nsecs_t mAppSwitchDueTime;
+    bool mAppSwitchSawKeyDown GUARDED_BY(mLock);
+    nsecs_t mAppSwitchDueTime GUARDED_BY(mLock);
 
-    static bool isAppSwitchKeyCode(int32_t keyCode);
-    bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry);
-    bool isAppSwitchPendingLocked();
-    void resetPendingAppSwitchLocked(bool handled);
+    bool isAppSwitchKeyEvent(KeyEntry* keyEntry);
+    bool isAppSwitchPendingLocked() REQUIRES(mLock);
+    void resetPendingAppSwitchLocked(bool handled) REQUIRES(mLock);
 
     // Stale event latency optimization.
-    static bool isStaleEventLocked(nsecs_t currentTime, EventEntry* entry);
+    static bool isStaleEvent(nsecs_t currentTime, EventEntry* entry);
 
     // Blocked event latency optimization.  Drops old events when the user intends
     // to transfer focus to a new application.
-    EventEntry* mNextUnblockedEvent;
+    EventEntry* mNextUnblockedEvent GUARDED_BY(mLock);
 
     sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y,
-            bool addOutsideTargets = false, bool addPortalWindows = false);
+            bool addOutsideTargets = false, bool addPortalWindows = false) REQUIRES(mLock);
 
     // All registered connections mapped by channel file descriptor.
-    KeyedVector<int, sp<Connection> > mConnectionsByFd;
+    KeyedVector<int, sp<Connection> > mConnectionsByFd GUARDED_BY(mLock);
 
     struct IBinderHash {
         std::size_t operator()(const sp<IBinder>& b) const {
             return std::hash<IBinder *>{}(b.get());
         }
     };
-    std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken;
+    std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken
+            GUARDED_BY(mLock);
 
-    ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
+    ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock);
 
     // Input channels that will receive a copy of all input events sent to the provided display.
-    std::unordered_map<int32_t, Vector<sp<InputChannel>>> mMonitoringChannelsByDisplay;
+    std::unordered_map<int32_t, Vector<sp<InputChannel>>> mMonitoringChannelsByDisplay
+            GUARDED_BY(mLock);
 
     // Event injection and synchronization.
     Condition mInjectionResultAvailableCondition;
@@ -945,17 +949,17 @@
     void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
 
     Condition mInjectionSyncFinishedCondition;
-    void incrementPendingForegroundDispatchesLocked(EventEntry* entry);
+    void incrementPendingForegroundDispatches(EventEntry* entry);
     void decrementPendingForegroundDispatchesLocked(EventEntry* entry);
 
     // Key repeat tracking.
     struct KeyRepeatState {
         KeyEntry* lastKeyEntry; // or null if no repeat
         nsecs_t nextRepeatTime;
-    } mKeyRepeatState;
+    } mKeyRepeatState GUARDED_BY(mLock);
 
-    void resetKeyRepeatLocked();
-    KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime);
+    void resetKeyRepeatLocked() REQUIRES(mLock);
+    KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime) REQUIRES(mLock);
 
     // Key replacement tracking
     struct KeyReplacement {
@@ -969,39 +973,42 @@
         }
     };
     // Maps the key code replaced, device id tuple to the key code it was replaced with
-    KeyedVector<KeyReplacement, int32_t> mReplacedKeys;
+    KeyedVector<KeyReplacement, int32_t> mReplacedKeys GUARDED_BY(mLock);
     // Process certain Meta + Key combinations
     void accelerateMetaShortcuts(const int32_t deviceId, const int32_t action,
             int32_t& keyCode, int32_t& metaState);
 
     // Deferred command processing.
-    bool haveCommandsLocked() const;
-    bool runCommandsLockedInterruptible();
-    CommandEntry* postCommandLocked(Command command);
+    bool haveCommandsLocked() const REQUIRES(mLock);
+    bool runCommandsLockedInterruptible() REQUIRES(mLock);
+    CommandEntry* postCommandLocked(Command command) REQUIRES(mLock);
 
     // Input filter processing.
-    bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args);
-    bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args);
+    bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock);
+    bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) REQUIRES(mLock);
 
     // Inbound event processing.
-    void drainInboundQueueLocked();
-    void releasePendingEventLocked();
-    void releaseInboundEventLocked(EventEntry* entry);
+    void drainInboundQueueLocked() REQUIRES(mLock);
+    void releasePendingEventLocked() REQUIRES(mLock);
+    void releaseInboundEventLocked(EventEntry* entry) REQUIRES(mLock);
 
     // Dispatch state.
-    bool mDispatchEnabled;
-    bool mDispatchFrozen;
-    bool mInputFilterEnabled;
+    bool mDispatchEnabled GUARDED_BY(mLock);
+    bool mDispatchFrozen GUARDED_BY(mLock);
+    bool mInputFilterEnabled GUARDED_BY(mLock);
 
-    std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay;
+    std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay
+            GUARDED_BY(mLock);
     // Get window handles by display, return an empty vector if not found.
-    Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const;
-    sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const;
-    sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const;
-    bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
+    Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const REQUIRES(mLock);
+    sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const
+            REQUIRES(mLock);
+    sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock);
+    bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
 
     // Focus tracking for keys, trackball, etc.
-    std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay;
+    std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay
+            GUARDED_BY(mLock);
 
     // Focus tracking for touch.
     struct TouchedWindow {
@@ -1036,34 +1043,35 @@
         bool isSlippery() const;
     };
 
-    KeyedVector<int32_t, TouchState> mTouchStatesByDisplay;
-    TouchState mTempTouchState;
+    KeyedVector<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock);
+    TouchState mTempTouchState GUARDED_BY(mLock);
 
     // Focused applications.
-    std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay;
+    std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay
+            GUARDED_BY(mLock);
 
     // Top focused display.
-    int32_t mFocusedDisplayId;
+    int32_t mFocusedDisplayId GUARDED_BY(mLock);
 
     // Dispatcher state at time of last ANR.
-    std::string mLastANRState;
+    std::string mLastANRState GUARDED_BY(mLock);
 
     // Dispatch inbound events.
     bool dispatchConfigurationChangedLocked(
-            nsecs_t currentTime, ConfigurationChangedEntry* entry);
+            nsecs_t currentTime, ConfigurationChangedEntry* entry) REQUIRES(mLock);
     bool dispatchDeviceResetLocked(
-            nsecs_t currentTime, DeviceResetEntry* entry);
+            nsecs_t currentTime, DeviceResetEntry* entry) REQUIRES(mLock);
     bool dispatchKeyLocked(
             nsecs_t currentTime, KeyEntry* entry,
-            DropReason* dropReason, nsecs_t* nextWakeupTime);
+            DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
     bool dispatchMotionLocked(
             nsecs_t currentTime, MotionEntry* entry,
-            DropReason* dropReason, nsecs_t* nextWakeupTime);
+            DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
     void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry,
-            const Vector<InputTarget>& inputTargets);
+            const Vector<InputTarget>& inputTargets) REQUIRES(mLock);
 
-    void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry);
-    void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry);
+    void logOutboundKeyDetails(const char* prefix, const KeyEntry* entry);
+    void logOutboundMotionDetails(const char* prefix, const MotionEntry* entry);
 
     // Keeping track of ANR timeouts.
     enum InputTargetWaitCause {
@@ -1072,130 +1080,133 @@
         INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY,
     };
 
-    InputTargetWaitCause mInputTargetWaitCause;
-    nsecs_t mInputTargetWaitStartTime;
-    nsecs_t mInputTargetWaitTimeoutTime;
-    bool mInputTargetWaitTimeoutExpired;
-    sp<IBinder> mInputTargetWaitApplicationToken;
+    InputTargetWaitCause mInputTargetWaitCause GUARDED_BY(mLock);
+    nsecs_t mInputTargetWaitStartTime GUARDED_BY(mLock);
+    nsecs_t mInputTargetWaitTimeoutTime GUARDED_BY(mLock);
+    bool mInputTargetWaitTimeoutExpired GUARDED_BY(mLock);
+    sp<IBinder> mInputTargetWaitApplicationToken GUARDED_BY(mLock);
 
     // Contains the last window which received a hover event.
-    sp<InputWindowHandle> mLastHoverWindowHandle;
+    sp<InputWindowHandle> mLastHoverWindowHandle GUARDED_BY(mLock);
 
     // Finding targets for input events.
     int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
             const sp<InputApplicationHandle>& applicationHandle,
             const sp<InputWindowHandle>& windowHandle,
-            nsecs_t* nextWakeupTime, const char* reason);
+            nsecs_t* nextWakeupTime, const char* reason) REQUIRES(mLock);
 
-    void removeWindowByTokenLocked(const sp<IBinder>& token);
+    void removeWindowByTokenLocked(const sp<IBinder>& token) REQUIRES(mLock);
 
     void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
-            const sp<InputChannel>& inputChannel);
-    nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime);
-    void resetANRTimeoutsLocked();
+            const sp<InputChannel>& inputChannel) REQUIRES(mLock);
+    nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) REQUIRES(mLock);
+    void resetANRTimeoutsLocked() REQUIRES(mLock);
 
     int32_t getTargetDisplayId(const EventEntry* entry);
     int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
-            Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime);
+            Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) REQUIRES(mLock);
     int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
             Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
-            bool* outConflictingPointerActions);
+            bool* outConflictingPointerActions) REQUIRES(mLock);
 
     void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
-            int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets);
+            int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets)
+            REQUIRES(mLock);
     void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets, int32_t displayId,
-            float xOffset = 0, float yOffset = 0);
+            float xOffset = 0, float yOffset = 0) REQUIRES(mLock);
 
-    void pokeUserActivityLocked(const EventEntry* eventEntry);
+    void pokeUserActivityLocked(const EventEntry* eventEntry) REQUIRES(mLock);
     bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
             const InjectionState* injectionState);
     bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
-            int32_t x, int32_t y) const;
-    bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const;
-    std::string getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
+            int32_t x, int32_t y) const REQUIRES(mLock);
+    bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
+    std::string getApplicationWindowLabel(const sp<InputApplicationHandle>& applicationHandle,
             const sp<InputWindowHandle>& windowHandle);
 
     std::string checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
             const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
-            const char* targetType);
+            const char* targetType) REQUIRES(mLock);
 
     // Manage the dispatch cycle for a single connection.
     // These methods are deliberately not Interruptible because doing all of the work
     // with the mutex held makes it easier to ensure that connection invariants are maintained.
     // If needed, the methods post commands to run later once the critical bits are done.
     void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            EventEntry* eventEntry, const InputTarget* inputTarget);
+            EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock);
     void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            EventEntry* eventEntry, const InputTarget* inputTarget);
+            EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock);
     void enqueueDispatchEntryLocked(const sp<Connection>& connection,
             EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode);
-    void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
+    void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
+            REQUIRES(mLock);
     void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            uint32_t seq, bool handled);
+            uint32_t seq, bool handled) REQUIRES(mLock);
     void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            bool notify);
+            bool notify) REQUIRES(mLock);
     void drainDispatchQueueLocked(Queue<DispatchEntry>* queue);
     void releaseDispatchEntryLocked(DispatchEntry* dispatchEntry);
     static int handleReceiveCallback(int fd, int events, void* data);
 
     void synthesizeCancelationEventsForAllConnectionsLocked(
-            const CancelationOptions& options);
-    void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options);
+            const CancelationOptions& options) REQUIRES(mLock);
+    void synthesizeCancelationEventsForMonitorsLocked(
+            const CancelationOptions& options) REQUIRES(mLock);
     void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
-            const CancelationOptions& options);
+            const CancelationOptions& options) REQUIRES(mLock);
     void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
-            const CancelationOptions& options);
+            const CancelationOptions& options) REQUIRES(mLock);
 
     // Splitting motion events across windows.
     MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds);
 
     // Reset and drop everything the dispatcher is doing.
-    void resetAndDropEverythingLocked(const char* reason);
+    void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock);
 
     // Dump state.
-    void dumpDispatchStateLocked(std::string& dump);
-    void logDispatchStateLocked();
+    void dumpDispatchStateLocked(std::string& dump) REQUIRES(mLock);
+    void logDispatchStateLocked() REQUIRES(mLock);
 
     // Registration.
-    void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel);
-    status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify);
-
-    // Add or remove a connection to the mActiveConnections vector.
-    void activateConnectionLocked(Connection* connection);
-    void deactivateConnectionLocked(Connection* connection);
+    void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock);
+    status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify)
+            REQUIRES(mLock);
 
     // Interesting events that we might like to log or tell the framework about.
     void onDispatchCycleFinishedLocked(
-            nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
+            nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled)
+             REQUIRES(mLock);
     void onDispatchCycleBrokenLocked(
-            nsecs_t currentTime, const sp<Connection>& connection);
+            nsecs_t currentTime, const sp<Connection>& connection) REQUIRES(mLock);
     void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
-            const sp<InputWindowHandle>& newFocus);
+            const sp<InputWindowHandle>& newFocus) REQUIRES(mLock);
     void onANRLocked(
             nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
             const sp<InputWindowHandle>& windowHandle,
-            nsecs_t eventTime, nsecs_t waitStartTime, const char* reason);
+            nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) REQUIRES(mLock);
 
     // Outbound policy interactions.
-    void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry);
-    void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
-    void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry);
-    void doNotifyANRLockedInterruptible(CommandEntry* commandEntry);
-    void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry);
-    void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry);
+    void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry)
+            REQUIRES(mLock);
+    void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+    void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+    void doNotifyANRLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+    void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry)
+            REQUIRES(mLock);
+    void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
     bool afterKeyEventLockedInterruptible(const sp<Connection>& connection,
-            DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled);
+            DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) REQUIRES(mLock);
     bool afterMotionEventLockedInterruptible(const sp<Connection>& connection,
             DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled);
-    void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry);
+    void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
     void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry);
 
     // Statistics gathering.
-    void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
+    void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry,
             int32_t injectionResult, nsecs_t timeSpentWaitingForApplication);
-    void traceInboundQueueLengthLocked();
-    void traceOutboundQueueLengthLocked(const sp<Connection>& connection);
-    void traceWaitQueueLengthLocked(const sp<Connection>& connection);
+    void traceInboundQueueLengthLocked() REQUIRES(mLock);
+    void traceOutboundQueueLength(const sp<Connection>& connection);
+    void traceWaitQueueLength(const sp<Connection>& connection);
 
     sp<InputReporterInterface> mReporter;
 };
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index e537e09..a403f31 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -28,12 +28,12 @@
 
 NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(
         uint32_t sequenceNum, nsecs_t eventTime) :
-        NotifyArgs(sequenceNum), eventTime(eventTime) {
+        NotifyArgs(sequenceNum, eventTime) {
 }
 
 NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(
         const NotifyConfigurationChangedArgs& other) :
-        NotifyArgs(other.sequenceNum), eventTime(other.eventTime) {
+        NotifyArgs(other.sequenceNum, other.eventTime) {
 }
 
 bool NotifyConfigurationChangedArgs::operator==(const NotifyConfigurationChangedArgs& rhs) const {
@@ -51,14 +51,14 @@
         uint32_t source, int32_t displayId, uint32_t policyFlags,
         int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
         int32_t metaState, nsecs_t downTime) :
-        NotifyArgs(sequenceNum), eventTime(eventTime), deviceId(deviceId), source(source),
+        NotifyArgs(sequenceNum, eventTime), deviceId(deviceId), source(source),
         displayId(displayId), policyFlags(policyFlags),
         action(action), flags(flags), keyCode(keyCode), scanCode(scanCode),
         metaState(metaState), downTime(downTime) {
 }
 
 NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) :
-        NotifyArgs(other.sequenceNum), eventTime(other.eventTime), deviceId(other.deviceId),
+        NotifyArgs(other.sequenceNum, other.eventTime), deviceId(other.deviceId),
         source(other.source), displayId(other.displayId), policyFlags(other.policyFlags),
         action(other.action), flags(other.flags),
         keyCode(other.keyCode), scanCode(other.scanCode),
@@ -95,7 +95,7 @@
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
         float xPrecision, float yPrecision, nsecs_t downTime,
         const std::vector<TouchVideoFrame>& videoFrames) :
-        NotifyArgs(sequenceNum), eventTime(eventTime), deviceId(deviceId), source(source),
+        NotifyArgs(sequenceNum, eventTime), deviceId(deviceId), source(source),
         displayId(displayId), policyFlags(policyFlags),
         action(action), actionButton(actionButton),
         flags(flags), metaState(metaState), buttonState(buttonState),
@@ -110,7 +110,7 @@
 }
 
 NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) :
-        NotifyArgs(other.sequenceNum), eventTime(other.eventTime), deviceId(other.deviceId),
+        NotifyArgs(other.sequenceNum, other.eventTime), deviceId(other.deviceId),
         source(other.source), displayId(other.displayId), policyFlags(other.policyFlags),
         action(other.action), actionButton(other.actionButton), flags(other.flags),
         metaState(other.metaState), buttonState(other.buttonState),
@@ -170,12 +170,12 @@
 
 NotifySwitchArgs::NotifySwitchArgs(uint32_t sequenceNum, nsecs_t eventTime, uint32_t policyFlags,
         uint32_t switchValues, uint32_t switchMask) :
-        NotifyArgs(sequenceNum), eventTime(eventTime), policyFlags(policyFlags),
+        NotifyArgs(sequenceNum, eventTime), policyFlags(policyFlags),
         switchValues(switchValues), switchMask(switchMask) {
 }
 
 NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) :
-        NotifyArgs(other.sequenceNum), eventTime(other.eventTime), policyFlags(other.policyFlags),
+        NotifyArgs(other.sequenceNum, other.eventTime), policyFlags(other.policyFlags),
         switchValues(other.switchValues), switchMask(other.switchMask) {
 }
 
@@ -196,11 +196,11 @@
 
 NotifyDeviceResetArgs::NotifyDeviceResetArgs(
         uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId) :
-        NotifyArgs(sequenceNum), eventTime(eventTime), deviceId(deviceId) {
+        NotifyArgs(sequenceNum, eventTime), deviceId(deviceId) {
 }
 
 NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) :
-        NotifyArgs(other.sequenceNum), eventTime(other.eventTime), deviceId(other.deviceId) {
+        NotifyArgs(other.sequenceNum, other.eventTime), deviceId(other.deviceId) {
 }
 
 bool NotifyDeviceResetArgs::operator==(const NotifyDeviceResetArgs& rhs) const {
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index b3b9e3e..b0157a1 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -84,6 +84,10 @@
     return mReader;
 }
 
+sp<InputClassifierInterface> InputManager::getClassifier() {
+    return mClassifier;
+}
+
 sp<InputDispatcherInterface> InputManager::getDispatcher() {
     return mDispatcher;
 }
@@ -99,7 +103,8 @@
     }
 };
 
-void InputManager::setInputWindows(const Vector<InputWindowInfo>& infos) {
+void InputManager::setInputWindows(const Vector<InputWindowInfo>& infos,
+        const sp<ISetInputWindowsListener>& setInputWindowsListener) {
     std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> handlesPerDisplay;
 
     Vector<sp<InputWindowHandle>> handles;
@@ -108,7 +113,7 @@
         handlesPerDisplay[info.displayId].add(new BinderWindowHandle(info));
     }
     for (auto const& i : handlesPerDisplay) {
-        mDispatcher->setInputWindows(i.second, i.first);
+        mDispatcher->setInputWindows(i.second, i.first, setInputWindowsListener);
     }
 }
 
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 142ec0c..ff9a080 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -29,6 +29,7 @@
 
 #include <input/Input.h>
 #include <input/InputTransport.h>
+#include <input/ISetInputWindowsListener.h>
 
 #include <input/IInputFlinger.h>
 #include <utils/Errors.h>
@@ -90,9 +91,11 @@
     virtual status_t stop();
 
     virtual sp<InputReaderInterface> getReader();
+    virtual sp<InputClassifierInterface> getClassifier();
     virtual sp<InputDispatcherInterface> getDispatcher();
 
-    virtual void setInputWindows(const Vector<InputWindowInfo>& handles);
+    virtual void setInputWindows(const Vector<InputWindowInfo>& handles,
+            const sp<ISetInputWindowsListener>& setInputWindowsListener);
     virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
 
     virtual void registerInputChannel(const sp<InputChannel>& channel);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index f84aa34..21ba029 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -4550,7 +4550,8 @@
             mPointerController->setButtonState(mCurrentRawState.buttonState);
             mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
                     mCurrentCookedState.cookedPointerData.idToIndex,
-                    mCurrentCookedState.cookedPointerData.touchingIdBits);
+                    mCurrentCookedState.cookedPointerData.touchingIdBits,
+                    mViewport.displayId);
         }
 
         if (!mCurrentMotionAborted) {
@@ -5314,7 +5315,8 @@
         if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
             mPointerController->setSpots(mPointerGesture.currentGestureCoords,
                      mPointerGesture.currentGestureIdToIndex,
-                     mPointerGesture.currentGestureIdBits);
+                     mPointerGesture.currentGestureIdBits,
+                     mPointerController->getDisplayId());
         }
     } else {
         mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
@@ -6563,6 +6565,8 @@
     const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE);
     const int32_t deviceId = getDeviceId();
     std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
+    std::for_each(frames.begin(), frames.end(),
+            [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
     NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
             source, displayId, policyFlags,
             action, actionButton, flags, metaState, buttonState, MotionClassification::NONE,
diff --git a/services/inputflinger/TouchVideoDevice.cpp b/services/inputflinger/TouchVideoDevice.cpp
index ad70ccc..76df3a1 100644
--- a/services/inputflinger/TouchVideoDevice.cpp
+++ b/services/inputflinger/TouchVideoDevice.cpp
@@ -37,10 +37,10 @@
 namespace android {
 
 TouchVideoDevice::TouchVideoDevice(int fd, std::string&& name, std::string&& devicePath,
-        uint32_t width, uint32_t height,
+        uint32_t height, uint32_t width,
         const std::array<const int16_t*, NUM_BUFFERS>& readLocations) :
         mFd(fd), mName(std::move(name)), mPath(std::move(devicePath)),
-        mWidth(width), mHeight(height),
+        mHeight(height), mWidth(width),
         mReadLocations(readLocations) {
     mFrames.reserve(MAX_QUEUE_SIZE);
 };
@@ -87,9 +87,9 @@
         ALOGE("VIDIOC_G_FMT failed: %s", strerror(errno));
         return nullptr;
     }
-    const uint32_t width = v4l2_fmt.fmt.pix.width;
     const uint32_t height = v4l2_fmt.fmt.pix.height;
-    ALOGI("Frame dimensions: width = %" PRIu32 " height = %" PRIu32, width, height);
+    const uint32_t width = v4l2_fmt.fmt.pix.width;
+    ALOGI("Frame dimensions: height = %" PRIu32 " width = %" PRIu32, height, width);
 
     struct v4l2_requestbuffers req;
     req.count = NUM_BUFFERS;
@@ -116,7 +116,7 @@
             ALOGE("VIDIOC_QUERYBUF failed: %s", strerror(errno));
             return nullptr;
         }
-        if (buf.length != width * height * sizeof(int16_t)) {
+        if (buf.length != height * width * sizeof(int16_t)) {
             ALOGE("Unexpected value of buf.length = %i (offset = %" PRIu32 ")",
                     buf.length, buf.m.offset);
             return nullptr;
@@ -148,7 +148,7 @@
     }
     // Using 'new' to access a non-public constructor.
     return std::unique_ptr<TouchVideoDevice>(new TouchVideoDevice(
-            fd.release(), std::move(name), std::move(devicePath), width, height, readLocations));
+            fd.release(), std::move(name), std::move(devicePath), height, width, readLocations));
 }
 
 size_t TouchVideoDevice::readAndQueueFrames() {
@@ -193,10 +193,10 @@
         ALOGW("The timestamp %ld.%ld was not acquired using CLOCK_MONOTONIC",
                 buf.timestamp.tv_sec, buf.timestamp.tv_usec);
     }
-    std::vector<int16_t> data(mWidth * mHeight);
+    std::vector<int16_t> data(mHeight * mWidth);
     const int16_t* readFrom = mReadLocations[buf.index];
-    std::copy(readFrom, readFrom + mWidth * mHeight, data.begin());
-    TouchVideoFrame frame(mWidth, mHeight, std::move(data), buf.timestamp);
+    std::copy(readFrom, readFrom + mHeight * mWidth, data.begin());
+    TouchVideoFrame frame(mHeight, mWidth, std::move(data), buf.timestamp);
 
     result = ioctl(mFd.get(), VIDIOC_QBUF, &buf);
     if (result == -1) {
@@ -230,7 +230,7 @@
     }
     for (const int16_t* buffer : mReadLocations) {
         void* bufferAddress = static_cast<void*>(const_cast<int16_t*>(buffer));
-        result = munmap(bufferAddress, mWidth * mHeight * sizeof(int16_t));
+        result = munmap(bufferAddress,  mHeight * mWidth * sizeof(int16_t));
         if (result == -1) {
             ALOGE("%s: Couldn't unmap: [%s]", __func__, strerror(errno));
         }
@@ -238,9 +238,9 @@
 }
 
 std::string TouchVideoDevice::dump() const {
-    return StringPrintf("Video device %s (%s) : width=%" PRIu32 ", height=%" PRIu32
+    return StringPrintf("Video device %s (%s) : height=%" PRIu32 ", width=%" PRIu32
             ", fd=%i, hasValidFd=%s",
-            mName.c_str(), mPath.c_str(), mWidth, mHeight, mFd.get(),
+            mName.c_str(), mPath.c_str(), mHeight, mWidth, mFd.get(),
             hasValidFd() ? "true" : "false");
 }
 
diff --git a/services/inputflinger/include/TouchVideoDevice.h b/services/inputflinger/TouchVideoDevice.h
similarity index 95%
rename from services/inputflinger/include/TouchVideoDevice.h
rename to services/inputflinger/TouchVideoDevice.h
index 7ff2653..0e7e2ef 100644
--- a/services/inputflinger/include/TouchVideoDevice.h
+++ b/services/inputflinger/TouchVideoDevice.h
@@ -54,14 +54,14 @@
      */
     const std::string& getPath() const { return mPath; }
     /**
-     * Get the width of the heatmap frame
-     */
-    uint32_t getWidth() const { return mWidth; }
-    /**
      * Get the height of the heatmap frame
      */
     uint32_t getHeight() const { return mHeight; }
     /**
+     * Get the width of the heatmap frame
+     */
+    uint32_t getWidth() const { return mWidth; }
+    /**
      * Direct read of the frame. Stores the frame into internal buffer.
      * Return the number of frames that were successfully read.
      *
@@ -73,6 +73,8 @@
     size_t readAndQueueFrames();
     /**
      * Return all of the queued frames, and erase them from the local buffer.
+     * The returned frames are in the order that they were received from the
+     * v4l2 device, with the oldest frame at the index 0.
      */
     std::vector<TouchVideoFrame> consumeFrames();
     /**
@@ -85,8 +87,8 @@
     std::string mName;
     std::string mPath;
 
-    uint32_t mWidth;
     uint32_t mHeight;
+    uint32_t mWidth;
 
     static constexpr int INVALID_FD = -1;
     /**
@@ -108,7 +110,7 @@
      * To get a new TouchVideoDevice, use 'create' instead.
      */
     explicit TouchVideoDevice(int fd, std::string&& name, std::string&& devicePath,
-            uint32_t width, uint32_t height,
+            uint32_t height, uint32_t width,
             const std::array<const int16_t*, NUM_BUFFERS>& readLocations);
     /**
      * Read all currently available frames.
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 9d0be95..a00b5fb 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -24,6 +24,7 @@
 
 #include <cutils/compiler.h>
 #include <input/IInputFlinger.h>
+#include <input/ISetInputWindowsListener.h>
 #include <utils/String8.h>
 #include <utils/String16.h>
 #include <utils/StrongPointer.h>
@@ -39,7 +40,7 @@
     InputFlinger() ANDROID_API;
 
     virtual status_t dump(int fd, const Vector<String16>& args);
-    void setInputWindows(const Vector<InputWindowInfo>&) {}
+    void setInputWindows(const Vector<InputWindowInfo>&, const sp<ISetInputWindowsListener>&) {}
     void transferTouchFocus(const sp<IBinder>&, const sp<IBinder>&) {}
     void registerInputChannel(const sp<InputChannel>&) {}
     void unregisterInputChannel(const sp<InputChannel>&) {}
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 13ae7dd..cd8caf7 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -32,10 +32,12 @@
 /* Superclass of all input event argument objects */
 struct NotifyArgs {
     uint32_t sequenceNum;
+    nsecs_t eventTime;
 
-    inline NotifyArgs() : sequenceNum(0) { }
+    inline NotifyArgs() : sequenceNum(0), eventTime(0) { }
 
-    inline explicit NotifyArgs(uint32_t sequenceNum) : sequenceNum(sequenceNum) { }
+    inline explicit NotifyArgs(uint32_t sequenceNum, nsecs_t eventTime) :
+            sequenceNum(sequenceNum), eventTime(eventTime) { }
 
     virtual ~NotifyArgs() { }
 
@@ -45,7 +47,6 @@
 
 /* Describes a configuration change event. */
 struct NotifyConfigurationChangedArgs : public NotifyArgs {
-    nsecs_t eventTime;
 
     inline NotifyConfigurationChangedArgs() { }
 
@@ -63,7 +64,6 @@
 
 /* Describes a key event. */
 struct NotifyKeyArgs : public NotifyArgs {
-    nsecs_t eventTime;
     int32_t deviceId;
     uint32_t source;
     int32_t displayId;
@@ -93,7 +93,6 @@
 
 /* Describes a motion event. */
 struct NotifyMotionArgs : public NotifyArgs {
-    nsecs_t eventTime;
     int32_t deviceId;
     uint32_t source;
     int32_t displayId;
@@ -146,7 +145,6 @@
 
 /* Describes a switch event. */
 struct NotifySwitchArgs : public NotifyArgs {
-    nsecs_t eventTime;
     uint32_t policyFlags;
     uint32_t switchValues;
     uint32_t switchMask;
@@ -169,7 +167,6 @@
 /* Describes a device reset event, such as when a device is added,
  * reconfigured, or removed. */
 struct NotifyDeviceResetArgs : public NotifyArgs {
-    nsecs_t eventTime;
     int32_t deviceId;
 
     inline NotifyDeviceResetArgs() { }
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index bc0f1f9..0ff28e4 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -94,7 +94,7 @@
      * pressed (not hovering).
      */
     virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
-            BitSet32 spotIdBits) = 0;
+            BitSet32 spotIdBits, int32_t displayId) = 0;
 
     /* Removes all spots. */
     virtual void clearSpots() = 0;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 0f987c3..3b6fe52 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -138,7 +138,7 @@
     virtual void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) {
     }
 
-    virtual void interceptMotionBeforeQueueing(nsecs_t, uint32_t&) {
+    virtual void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) {
     }
 
     virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&,
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 84c5ad6..80a55f1 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -103,6 +103,10 @@
         return mDisplayId;
     }
 
+    const std::map<int32_t, std::vector<int32_t>>& getSpots() {
+        return mSpotsByDisplay;
+    }
+
 private:
     virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const {
         *outMinX = mMinX;
@@ -130,11 +134,22 @@
     virtual void setPresentation(Presentation) {
     }
 
-    virtual void setSpots(const PointerCoords*, const uint32_t*, BitSet32) {
+    virtual void setSpots(const PointerCoords*, const uint32_t*, BitSet32 spotIdBits,
+            int32_t displayId) {
+        std::vector<int32_t> newSpots;
+        // Add spots for fingers that are down.
+        for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
+            uint32_t id = idBits.clearFirstMarkedBit();
+            newSpots.push_back(id);
+        }
+
+        mSpotsByDisplay[displayId] = newSpots;
     }
 
     virtual void clearSpots() {
     }
+
+    std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay;
 };
 
 
@@ -228,6 +243,10 @@
         mConfig.pointerCapture = enabled;
     }
 
+    void setShowTouches(bool enabled) {
+        mConfig.showTouches = enabled;
+    }
+
 private:
     DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
             int32_t orientation, const std::string& uniqueId, std::optional<uint8_t> physicalPort,
@@ -316,6 +335,7 @@
     KeyedVector<int32_t, Device*> mDevices;
     std::vector<std::string> mExcludedDevices;
     List<RawEvent> mEvents;
+    std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
 
 protected:
     virtual ~FakeEventHub() {
@@ -480,6 +500,11 @@
         }
     }
 
+    void setVideoFrames(std::unordered_map<int32_t /*deviceId*/,
+            std::vector<TouchVideoFrame>> videoFrames) {
+        mVideoFrames = std::move(videoFrames);
+    }
+
     void assertQueueIsEmpty() {
         ASSERT_EQ(size_t(0), mEvents.size())
                 << "Expected the event queue to be empty (fully consumed).";
@@ -595,6 +620,12 @@
     }
 
     virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) {
+        auto it = mVideoFrames.find(deviceId);
+        if (it != mVideoFrames.end()) {
+            std::vector<TouchVideoFrame> frames = std::move(it->second);
+            mVideoFrames.erase(deviceId);
+            return frames;
+        }
         return {};
     }
 
@@ -6315,4 +6346,159 @@
     ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
 }
 
+TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) {
+    // Setup the first touch screen device.
+    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+    prepareAxes(POSITION | ID | SLOT);
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    addMapperAndConfigure(mapper);
+
+    // Create the second touch screen device, and enable multi fingers.
+    const std::string USB2 = "USB2";
+    const int32_t SECOND_DEVICE_ID = 2;
+    InputDeviceIdentifier identifier;
+    identifier.name = DEVICE_NAME;
+    identifier.location = USB2;
+    InputDevice* device2 = new InputDevice(mFakeContext, SECOND_DEVICE_ID, DEVICE_GENERATION,
+            DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
+    mFakeEventHub->addDevice(SECOND_DEVICE_ID, DEVICE_NAME, 0 /*classes*/);
+    mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX,
+            0 /*flat*/, 0 /*fuzz*/);
+    mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX,
+            0 /*flat*/, 0 /*fuzz*/);
+    mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_TRACKING_ID, RAW_ID_MIN, RAW_ID_MAX,
+            0 /*flat*/, 0 /*fuzz*/);
+    mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_SLOT, RAW_SLOT_MIN, RAW_SLOT_MAX,
+            0 /*flat*/, 0 /*fuzz*/);
+    mFakeEventHub->setAbsoluteAxisValue(SECOND_DEVICE_ID, ABS_MT_SLOT, 0 /*value*/);
+    mFakeEventHub->addConfigurationProperty(SECOND_DEVICE_ID, String8("touch.deviceType"),
+            String8("touchScreen"));
+
+    // Setup the second touch screen device.
+    MultiTouchInputMapper* mapper2 = new MultiTouchInputMapper(device2);
+    device2->addMapper(mapper2);
+    device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
+    device2->reset(ARBITRARY_TIME);
+
+    // Setup PointerController.
+    sp<FakePointerController> fakePointerController = new FakePointerController();
+    mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+    mFakePolicy->setPointerController(SECOND_DEVICE_ID, fakePointerController);
+
+    // Setup policy for associated displays and show touches.
+    const uint8_t hdmi1 = 0;
+    const uint8_t hdmi2 = 1;
+    mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1);
+    mFakePolicy->addInputPortAssociation(USB2, hdmi2);
+    mFakePolicy->setShowTouches(true);
+
+    // Create displays.
+    prepareDisplay(DISPLAY_ORIENTATION_0, hdmi1);
+    prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL, hdmi2);
+
+    // Default device will reconfigure above, need additional reconfiguration for another device.
+    device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+            InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+    // Two fingers down at default display.
+    int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500;
+    processPosition(mapper, x1, y1);
+    processId(mapper, 1);
+    processSlot(mapper, 1);
+    processPosition(mapper, x2, y2);
+    processId(mapper, 2);
+    processSync(mapper);
+
+    std::map<int32_t, std::vector<int32_t>>::const_iterator iter =
+            fakePointerController->getSpots().find(DISPLAY_ID);
+    ASSERT_TRUE(iter != fakePointerController->getSpots().end());
+    ASSERT_EQ(size_t(2), iter->second.size());
+
+    // Two fingers down at second display.
+    processPosition(mapper2, x1, y1);
+    processId(mapper2, 1);
+    processSlot(mapper2, 1);
+    processPosition(mapper2, x2, y2);
+    processId(mapper2, 2);
+    processSync(mapper2);
+
+    iter = fakePointerController->getSpots().find(SECONDARY_DISPLAY_ID);
+    ASSERT_TRUE(iter != fakePointerController->getSpots().end());
+    ASSERT_EQ(size_t(2), iter->second.size());
+}
+
+TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) {
+    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+    prepareAxes(POSITION);
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    addMapperAndConfigure(mapper);
+
+    NotifyMotionArgs motionArgs;
+    // Unrotated video frame
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
+    std::vector<TouchVideoFrame> frames{frame};
+    mFakeEventHub->setVideoFrames({{mDevice->getId(), frames}});
+    processPosition(mapper, 100, 200);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(frames, motionArgs.videoFrames);
+
+    // Subsequent touch events should not have any videoframes
+    // This is implemented separately in FakeEventHub,
+    // but that should match the behaviour of TouchVideoDevice.
+    processPosition(mapper, 200, 200);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(std::vector<TouchVideoFrame>(), motionArgs.videoFrames);
+}
+
+TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) {
+    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+    prepareAxes(POSITION);
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    addMapperAndConfigure(mapper);
+    // Unrotated video frame
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
+    NotifyMotionArgs motionArgs;
+
+    // Test all 4 orientations
+    for (int32_t orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90,
+             DISPLAY_ORIENTATION_180, DISPLAY_ORIENTATION_270}) {
+        SCOPED_TRACE("Orientation " + StringPrintf("%i", orientation));
+        clearViewports();
+        prepareDisplay(orientation);
+        std::vector<TouchVideoFrame> frames{frame};
+        mFakeEventHub->setVideoFrames({{mDevice->getId(), frames}});
+        processPosition(mapper, 100, 200);
+        processSync(mapper);
+        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+        frames[0].rotate(orientation);
+        ASSERT_EQ(frames, motionArgs.videoFrames);
+    }
+}
+
+TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreRotated) {
+    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+    prepareAxes(POSITION);
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    addMapperAndConfigure(mapper);
+    // Unrotated video frames. There's no rule that they must all have the same dimensions,
+    // so mix these.
+    TouchVideoFrame frame1(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
+    TouchVideoFrame frame2(3, 3, {0, 1, 2, 3, 4, 5, 6, 7, 8}, {1, 3});
+    TouchVideoFrame frame3(2, 2, {10, 20, 10, 0}, {1, 4});
+    std::vector<TouchVideoFrame> frames{frame1, frame2, frame3};
+    NotifyMotionArgs motionArgs;
+
+    prepareDisplay(DISPLAY_ORIENTATION_90);
+    mFakeEventHub->setVideoFrames({{mDevice->getId(), frames}});
+    processPosition(mapper, 100, 200);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    std::for_each(frames.begin(), frames.end(),
+            [](TouchVideoFrame& frame) { frame.rotate(DISPLAY_ORIENTATION_90); });
+    ASSERT_EQ(frames, motionArgs.videoFrames);
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 734ed6c..3304fd1 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -142,6 +142,7 @@
         "MonitoredProducer.cpp",
         "NativeWindowSurface.cpp",
         "RenderArea.cpp",
+        "RegionSamplingThread.cpp",
         "Scheduler/DispSync.cpp",
         "Scheduler/DispSyncSource.cpp",
         "Scheduler/EventControlThread.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 65308a6..2501fae 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -24,8 +24,12 @@
 #include <mutex>
 
 #include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
 #include <compositionengine/Layer.h>
 #include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <cutils/compiler.h>
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
@@ -57,8 +61,6 @@
                 compositionengine::LayerCreationArgs{this})} {
     ALOGV("Creating Layer %s", args.name.string());
 
-    mTexture.init(renderengine::Texture::TEXTURE_EXTERNAL, mTextureName);
-
     mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
 
     mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow;
@@ -67,14 +69,6 @@
 
 BufferLayer::~BufferLayer() {
     mFlinger->deleteTextureAsync(mTextureName);
-
-    if (!getBE().mHwcLayers.empty()) {
-        ALOGE("Found stale hardware composer layers when destroying "
-              "surface flinger layer %s",
-              mName.string());
-        destroyAllHwcLayersPlusChildren();
-    }
-
     mFlinger->mTimeStats->onDestroy(getSequence());
 }
 
@@ -93,7 +87,7 @@
 bool BufferLayer::isOpaque(const Layer::State& s) const {
     // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
     // layer's opaque flag.
-    if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
+    if ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
         return false;
     }
 
@@ -104,7 +98,7 @@
 
 bool BufferLayer::isVisible() const {
     return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
-            (mActiveBuffer != nullptr || getBE().compositionInfo.hwc.sidebandStream != nullptr);
+            (mActiveBuffer != nullptr || mSidebandStream != nullptr);
 }
 
 bool BufferLayer::isFixedSize() const {
@@ -129,13 +123,11 @@
     return inverse(tr);
 }
 
-/*
- * onDraw will draw the current layer onto the presentable buffer
- */
-void BufferLayer::onDraw(const RenderArea& renderArea, const Region& clip,
-                         bool useIdentityTransform) {
+bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+                                     bool useIdentityTransform, Region& clearRegion,
+                                     renderengine::LayerSettings& layer) {
     ATRACE_CALL();
-
+    Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, layer);
     if (CC_UNLIKELY(mActiveBuffer == 0)) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
@@ -153,32 +145,30 @@
                 finished = true;
                 return;
             }
-            under.orSelf(renderArea.getTransform().transform(layer->visibleRegion));
+            under.orSelf(layer->visibleRegion);
         });
         // if not everything below us is covered, we plug the holes!
         Region holes(clip.subtract(under));
         if (!holes.isEmpty()) {
-            clearWithOpenGL(renderArea, 0, 0, 0, 1);
+            clearRegion.orSelf(holes);
         }
-        return;
+        return false;
     }
-
-    // Bind the current buffer to the GL texture, and wait for it to be
-    // ready for us to draw into.
-    status_t err = bindTextureImage();
-    if (err != NO_ERROR) {
-        ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
-        // Go ahead and draw the buffer anyway; no matter what we do the screen
-        // is probably going to have something visibly wrong.
-    }
-
     bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure());
-
-    auto& engine(mFlinger->getRenderEngine());
-
+    const State& s(getDrawingState());
     if (!blackOutLayer) {
+        layer.source.buffer.buffer = mActiveBuffer;
+        layer.source.buffer.isOpaque = isOpaque(s);
+        layer.source.buffer.fence = mActiveBufferFence;
+        layer.source.buffer.cacheHint = useCachedBufferForClientComposition()
+                ? renderengine::Buffer::CachingHint::USE_CACHE
+                : renderengine::Buffer::CachingHint::NO_CACHE;
+        layer.source.buffer.textureName = mTextureName;
+        layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
+        layer.source.buffer.isY410BT2020 = isHdrY410();
         // TODO: we could be more subtle with isFixedSize()
-        const bool useFiltering = needsFiltering() || renderArea.needsFiltering() || isFixedSize();
+        const bool useFiltering = needsFiltering(renderArea.getDisplayDevice()) ||
+                renderArea.needsFiltering() || isFixedSize();
 
         // Query the texture matrix given our current filtering mode.
         float textureMatrix[16];
@@ -213,43 +203,62 @@
             memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
         }
 
-        // Set things up for texturing.
-        mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
-        mTexture.setFiltering(useFiltering);
-        mTexture.setMatrix(textureMatrix);
+        const Rect win{getBounds()};
+        const float bufferWidth = getBufferSize(s).getWidth();
+        const float bufferHeight = getBufferSize(s).getHeight();
 
-        engine.setupLayerTexturing(mTexture);
+        const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
+        const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
+        const float translateY = float(win.top) / bufferHeight;
+        const float translateX = float(win.left) / bufferWidth;
+
+        // Flip y-coordinates because GLConsumer expects OpenGL convention.
+        mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) *
+                mat4::translate(vec4(-.5, -.5, 0, 1)) *
+                mat4::translate(vec4(translateX, translateY, 0, 1)) *
+                mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0));
+
+        layer.source.buffer.useTextureFiltering = useFiltering;
+        layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr;
     } else {
-        engine.setupLayerBlackedOut();
+        // If layer is blacked out, force alpha to 1 so that we draw a black color
+        // layer.
+        layer.source.buffer.buffer = nullptr;
+        layer.alpha = 1.0;
     }
-    drawWithOpenGL(renderArea, useIdentityTransform);
-    engine.disableTexturing();
+
+    return true;
 }
 
 bool BufferLayer::isHdrY410() const {
     // pixel format is HDR Y410 masquerading as RGBA_1010102
     return (mCurrentDataSpace == ui::Dataspace::BT2020_ITU_PQ &&
             getDrawingApi() == NATIVE_WINDOW_API_MEDIA &&
-            getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
+            mActiveBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
 }
 
-void BufferLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
-                                  const Rect& viewport, int32_t supportedPerFrameMetadata) {
-    RETURN_IF_NO_HWC_LAYER(displayId);
+void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice,
+                                  const ui::Transform& transform, const Rect& viewport,
+                                  int32_t supportedPerFrameMetadata) {
+    RETURN_IF_NO_HWC_LAYER(displayDevice);
 
     // Apply this display's projection's viewport to the visible region
     // before giving it to the HWC HAL.
     Region visible = transform.transform(visibleRegion.intersect(viewport));
 
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
-    auto& hwcLayer = hwcInfo.layer;
+    const auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
+
+    auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
     auto error = hwcLayer->setVisibleRegion(visible);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
               to_string(error).c_str(), static_cast<int32_t>(error));
         visible.dump(LOG_TAG);
     }
-    getBE().compositionInfo.hwc.visibleRegion = visible;
+    outputLayer->editState().visibleRegion = visible;
+
+    auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
 
     error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
     if (error != HWC2::Error::None) {
@@ -257,29 +266,29 @@
               to_string(error).c_str(), static_cast<int32_t>(error));
         surfaceDamageRegion.dump(LOG_TAG);
     }
-    getBE().compositionInfo.hwc.surfaceDamage = surfaceDamageRegion;
+    layerCompositionState.surfaceDamage = surfaceDamageRegion;
 
     // Sideband layers
-    if (getBE().compositionInfo.hwc.sidebandStream.get()) {
-        setCompositionType(displayId, HWC2::Composition::Sideband);
+    if (layerCompositionState.sidebandStream.get()) {
+        setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::SIDEBAND);
         ALOGV("[%s] Requesting Sideband composition", mName.string());
-        error = hwcLayer->setSidebandStream(getBE().compositionInfo.hwc.sidebandStream->handle());
+        error = hwcLayer->setSidebandStream(layerCompositionState.sidebandStream->handle());
         if (error != HWC2::Error::None) {
             ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
-                  getBE().compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(),
+                  layerCompositionState.sidebandStream->handle(), to_string(error).c_str(),
                   static_cast<int32_t>(error));
         }
-        getBE().compositionInfo.compositionType = HWC2::Composition::Sideband;
+        layerCompositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
         return;
     }
 
     // Device or Cursor layers
     if (mPotentialCursor) {
         ALOGV("[%s] Requesting Cursor composition", mName.string());
-        setCompositionType(displayId, HWC2::Composition::Cursor);
+        setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CURSOR);
     } else {
         ALOGV("[%s] Requesting Device composition", mName.string());
-        setCompositionType(displayId, HWC2::Composition::Device);
+        setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE);
     }
 
     ALOGV("setPerFrameData: dataspace = %d", mCurrentDataSpace);
@@ -301,12 +310,11 @@
         ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
                 to_string(error).c_str(), static_cast<int32_t>(error));
     }
-    getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
-    getBE().compositionInfo.hwc.hdrMetadata = getDrawingHdrMetadata();
-    getBE().compositionInfo.hwc.supportedPerFrameMetadata = supportedPerFrameMetadata;
-    getBE().compositionInfo.hwc.colorTransform = getColorTransform();
+    layerCompositionState.dataspace = mCurrentDataSpace;
+    layerCompositionState.colorTransform = getColorTransform();
+    layerCompositionState.hdrMetadata = metadata;
 
-    setHwcLayerBuffer(displayId);
+    setHwcLayerBuffer(displayDevice);
 }
 
 bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
@@ -365,20 +373,17 @@
     return true;
 }
 
-Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                                const sp<Fence>& releaseFence) {
+bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
     ATRACE_CALL();
 
-    std::optional<Region> sidebandStreamDirtyRegion = latchSidebandStream(recomputeVisibleRegions);
+    bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
 
-    if (sidebandStreamDirtyRegion) {
-        return *sidebandStreamDirtyRegion;
+    if (refreshRequired) {
+        return refreshRequired;
     }
 
-    Region dirtyRegion;
-
     if (!hasReadyFrame()) {
-        return dirtyRegion;
+        return false;
     }
 
     // if we've already called updateTexImage() without going through
@@ -387,14 +392,14 @@
     // compositionComplete() call.
     // we'll trigger an update in onPreComposition().
     if (mRefreshPending) {
-        return dirtyRegion;
+        return false;
     }
 
     // If the head buffer's acquire fence hasn't signaled yet, return and
     // try again later
     if (!fenceHasSignaled()) {
         mFlinger->signalLayerUpdate();
-        return dirtyRegion;
+        return false;
     }
 
     // Capture the old state of the layer for comparisons later
@@ -404,24 +409,24 @@
 
     if (!allTransactionsSignaled()) {
         mFlinger->signalLayerUpdate();
-        return dirtyRegion;
+        return false;
     }
 
-    status_t err = updateTexImage(recomputeVisibleRegions, latchTime, releaseFence);
+    status_t err = updateTexImage(recomputeVisibleRegions, latchTime);
     if (err != NO_ERROR) {
-        return dirtyRegion;
+        return false;
     }
 
     err = updateActiveBuffer();
     if (err != NO_ERROR) {
-        return dirtyRegion;
+        return false;
     }
 
     mBufferLatched = true;
 
     err = updateFrameNumber(latchTime);
     if (err != NO_ERROR) {
-        return dirtyRegion;
+        return false;
     }
 
     mRefreshPending = true;
@@ -461,11 +466,14 @@
     Rect crop(getDrawingCrop());
     const uint32_t transform(getDrawingTransform());
     const uint32_t scalingMode(getDrawingScalingMode());
+    const bool transformToDisplayInverse(getTransformToDisplayInverse());
     if ((crop != mCurrentCrop) || (transform != mCurrentTransform) ||
-        (scalingMode != mCurrentScalingMode)) {
+        (scalingMode != mCurrentScalingMode) ||
+        (transformToDisplayInverse != mTransformToDisplayInverse)) {
         mCurrentCrop = crop;
         mCurrentTransform = transform;
         mCurrentScalingMode = scalingMode;
+        mTransformToDisplayInverse = transformToDisplayInverse;
         recomputeVisibleRegions = true;
     }
 
@@ -502,9 +510,7 @@
         }
     }
 
-    // FIXME: postedRegion should be dirty & bounds
-    // transform the dirty region to window-manager space
-    return getTransform().transform(Region(getBufferSize(s)));
+    return true;
 }
 
 // transaction
@@ -599,72 +605,23 @@
     return true;
 }
 
-bool BufferLayer::needsFiltering() const {
-    const auto displayFrame = getBE().compositionInfo.hwc.displayFrame;
-    const auto sourceCrop = getBE().compositionInfo.hwc.sourceCrop;
-    return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
-            sourceCrop.getWidth() != displayFrame.getWidth();
-}
-
-void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
-    ATRACE_CALL();
-    const State& s(getDrawingState());
-
-    computeGeometry(renderArea, getBE().mMesh, useIdentityTransform);
-
-    /*
-     * NOTE: the way we compute the texture coordinates here produces
-     * different results than when we take the HWC path -- in the later case
-     * the "source crop" is rounded to texel boundaries.
-     * This can produce significantly different results when the texture
-     * is scaled by a large amount.
-     *
-     * The GL code below is more logical (imho), and the difference with
-     * HWC is due to a limitation of the HWC API to integers -- a question
-     * is suspend is whether we should ignore this problem or revert to
-     * GL composition when a buffer scaling is applied (maybe with some
-     * minimal value)? Or, we could make GL behave like HWC -- but this feel
-     * like more of a hack.
-     */
-    const Rect bounds{computeBounds()}; // Rounds from FloatRect
-
-    Rect win = bounds;
-    const int bufferWidth = getBufferSize(s).getWidth();
-    const int bufferHeight = getBufferSize(s).getHeight();
-
-    const float left = float(win.left) / float(bufferWidth);
-    const float top = float(win.top) / float(bufferHeight);
-    const float right = float(win.right) / float(bufferWidth);
-    const float bottom = float(win.bottom) / float(bufferHeight);
-
-    // TODO: we probably want to generate the texture coords with the mesh
-    // here we assume that we only have 4 vertices
-    renderengine::Mesh::VertexArray<vec2> texCoords(getBE().mMesh.getTexCoordArray<vec2>());
-    // flip texcoords vertically because BufferLayerConsumer expects them to be in GL convention
-    texCoords[0] = vec2(left, 1.0f - top);
-    texCoords[1] = vec2(left, 1.0f - bottom);
-    texCoords[2] = vec2(right, 1.0f - bottom);
-    texCoords[3] = vec2(right, 1.0f - top);
-
-    const auto roundedCornerState = getRoundedCornerState();
-    const auto cropRect = roundedCornerState.cropRect;
-    setupRoundedCornersCropCoordinates(win, cropRect);
-
-    auto& engine(mFlinger->getRenderEngine());
-    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), false /* disableTexture */,
-                              getColor(), roundedCornerState.radius);
-    engine.setSourceDataSpace(mCurrentDataSpace);
-
-    if (isHdrY410()) {
-        engine.setSourceY410BT2020(true);
+bool BufferLayer::needsFiltering(const sp<const DisplayDevice>& displayDevice) const {
+    // If we are not capturing based on the state of a known display device, we
+    // only return mNeedsFiltering
+    if (displayDevice == nullptr) {
+        return mNeedsFiltering;
     }
 
-    engine.setupCornerRadiusCropSize(cropRect.getWidth(), cropRect.getHeight());
+    const auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    if (outputLayer == nullptr) {
+        return mNeedsFiltering;
+    }
 
-    engine.drawMesh(getBE().mMesh);
-    engine.disableBlending();
-
-    engine.setSourceY410BT2020(false);
+    const auto& compositionState = outputLayer->getState();
+    const auto displayFrame = compositionState.displayFrame;
+    const auto sourceCrop = compositionState.sourceCrop;
+    return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
+            sourceCrop.getWidth() != displayFrame.getWidth();
 }
 
 uint64_t BufferLayer::getHeadFrameNumber() const {
@@ -709,6 +666,38 @@
     return mCompositionLayer;
 }
 
+FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const {
+    const State& s(getDrawingState());
+
+    // If we have a sideband stream, or we are scaling the buffer then return the layer size since
+    // we cannot determine the buffer size.
+    if ((s.sidebandStream != nullptr) ||
+        (getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE)) {
+        return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s));
+    }
+
+    if (mActiveBuffer == nullptr) {
+        return parentBounds;
+    }
+
+    uint32_t bufWidth = mActiveBuffer->getWidth();
+    uint32_t bufHeight = mActiveBuffer->getHeight();
+
+    // Undo any transformations on the buffer and return the result.
+    if (mCurrentTransform & ui::Transform::ROT_90) {
+        std::swap(bufWidth, bufHeight);
+    }
+
+    if (getTransformToDisplayInverse()) {
+        uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+        if (invTransform & ui::Transform::ROT_90) {
+            std::swap(bufWidth, bufHeight);
+        }
+    }
+
+    return FloatRect(0, 0, bufWidth, bufHeight);
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 8158d6c..e3b10fc 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -22,6 +22,7 @@
 
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerState.h>
+#include <renderengine/Image.h>
 #include <renderengine/Mesh.h>
 #include <renderengine/Texture.h>
 #include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE
@@ -77,14 +78,10 @@
     // isFixedSize - true if content has a fixed size
     bool isFixedSize() const override;
 
-    // onDraw - draws the surface.
-    void onDraw(const RenderArea& renderArea, const Region& clip,
-                bool useIdentityTransform) override;
-
     bool isHdrY410() const override;
 
-    void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
-                         int32_t supportedPerFrameMetadata) override;
+    void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
+                         const Rect& viewport, int32_t supportedPerFrameMetadata) override;
 
     bool onPreComposition(nsecs_t refreshStartTime) override;
     bool onPostComposition(const std::optional<DisplayId>& displayId,
@@ -96,11 +93,7 @@
     // the visible regions need to be recomputed (this is a fairly heavy
     // operation, so this should be set only if needed). Typically this is used
     // to figure out if the content or size of a surface has changed.
-    // If there was a GL composition step rendering the previous frame, then
-    // releaseFence will be populated with a native fence that fires when
-    // composition has completed.
-    Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                       const sp<Fence>& releaseFence) override;
+    bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
 
     bool isBufferLatched() const override { return mRefreshPending; }
 
@@ -137,20 +130,20 @@
     virtual bool getAutoRefresh() const = 0;
     virtual bool getSidebandStreamChanged() const = 0;
 
-    virtual std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) = 0;
+    // Latch sideband stream and returns true if the dirty region should be updated.
+    virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0;
 
     virtual bool hasFrameUpdate() const = 0;
 
     virtual void setFilteringEnabled(bool enabled) = 0;
 
     virtual status_t bindTextureImage() = 0;
-    virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                                    const sp<Fence>& flushFence) = 0;
+    virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0;
 
     virtual status_t updateActiveBuffer() = 0;
     virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
 
-    virtual void setHwcLayerBuffer(DisplayId displayId) = 0;
+    virtual void setHwcLayerBuffer(const sp<const DisplayDevice>& displayDevice) = 0;
 
 protected:
     // Loads the corresponding system property once per process
@@ -168,26 +161,33 @@
 
     bool mRefreshPending{false};
 
+    // Returns true if, when drawing the active buffer during gpu compositon, we
+    // should use a cached buffer or not.
+    virtual bool useCachedBufferForClientComposition() const = 0;
+
+    // prepareClientLayer - constructs a RenderEngine layer for GPU composition.
+    bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+                            bool useIdentityTransform, Region& clearRegion,
+                            renderengine::LayerSettings& layer);
+
 private:
     // Returns true if this layer requires filtering
-    bool needsFiltering() const;
-
-    // drawing
-    void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
+    bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const;
 
     uint64_t getHeadFrameNumber() const;
 
     uint32_t mCurrentScalingMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
 
+    bool mTransformToDisplayInverse{false};
+
     // main thread.
     bool mBufferLatched{false}; // TODO: Use mActiveBuffer?
 
-    // The texture used to draw the layer in GLES composition mode
-    mutable renderengine::Texture mTexture;
-
     Rect getBufferSize(const State& s) const override;
 
     std::shared_ptr<compositionengine::Layer> mCompositionLayer;
+
+    FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 6826050..6866e5c 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -100,8 +100,7 @@
 
 status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
                                              bool* autoRefresh, bool* queuedBuffer,
-                                             uint64_t maxFrameNumber,
-                                             const sp<Fence>& releaseFence) {
+                                             uint64_t maxFrameNumber) {
     ATRACE_CALL();
     BLC_LOGV("updateTexImage");
     Mutex::Autolock lock(mMutex);
@@ -146,7 +145,7 @@
     }
 
     // Release the previous buffer.
-    err = updateAndReleaseLocked(item, &mPendingRelease, releaseFence);
+    err = updateAndReleaseLocked(item, &mPendingRelease);
     if (err != NO_ERROR) {
         return err;
     }
@@ -224,25 +223,11 @@
 }
 
 status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
-                                                     PendingRelease* pendingRelease,
-                                                     const sp<Fence>& releaseFence) {
+                                                     PendingRelease* pendingRelease) {
     status_t err = NO_ERROR;
 
     int slot = item.mSlot;
 
-    // Do whatever sync ops we need to do before releasing the old slot.
-    if (slot != mCurrentTexture) {
-        err = syncForReleaseLocked(releaseFence);
-        if (err != NO_ERROR) {
-            // Release the buffer we just acquired.  It's not safe to
-            // release the old buffer, so instead we just drop the new frame.
-            // As we are still under lock since acquireBuffer, it is safe to
-            // release by slot.
-            releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
-            return err;
-        }
-    }
-
     BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
              mCurrentTextureBuffer != nullptr ? mCurrentTextureBuffer->handle : 0, slot,
              mSlots[slot].mGraphicBuffer->handle);
@@ -272,6 +257,7 @@
     // Update the BufferLayerConsumer state.
     mCurrentTexture = slot;
     mCurrentTextureBuffer = nextTextureBuffer;
+    mCurrentTextureBufferStaleForGpu = false;
     mCurrentTextureImageFreed = nullptr;
     mCurrentCrop = item.mCrop;
     mCurrentTransform = item.mTransform;
@@ -294,72 +280,7 @@
 status_t BufferLayerConsumer::bindTextureImageLocked() {
     ATRACE_CALL();
 
-    mRE.checkErrors();
-
-    // It is possible for the current slot's buffer to be freed before a new one
-    // is bound. In that scenario we still want to bind the image.
-    if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureBuffer == nullptr) {
-        BLC_LOGE("bindTextureImage: no currently-bound texture");
-        mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
-        return NO_INIT;
-    }
-
-    renderengine::Image* imageToRender;
-
-    // mCurrentTextureImageFreed is non-null iff mCurrentTexture ==
-    // BufferQueue::INVALID_BUFFER_SLOT, so we can omit that check.
-    if (mCurrentTextureImageFreed) {
-        imageToRender = mCurrentTextureImageFreed.get();
-    } else if (mImages[mCurrentTexture]) {
-        imageToRender = mImages[mCurrentTexture].get();
-    } else {
-        std::unique_ptr<renderengine::Image> image = mRE.createImage();
-        bool success = image->setNativeWindowBuffer(mCurrentTextureBuffer->getNativeBuffer(),
-                                                    mCurrentTextureBuffer->getUsage() &
-                                                            GRALLOC_USAGE_PROTECTED);
-        if (!success) {
-            BLC_LOGE("bindTextureImage: Failed to create image. size=%ux%u st=%u usage=%#" PRIx64
-                     " fmt=%d",
-                     mCurrentTextureBuffer->getWidth(), mCurrentTextureBuffer->getHeight(),
-                     mCurrentTextureBuffer->getStride(), mCurrentTextureBuffer->getUsage(),
-                     mCurrentTextureBuffer->getPixelFormat());
-            BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
-            mRE.bindExternalTextureImage(mTexName, *image);
-            return UNKNOWN_ERROR;
-        }
-        imageToRender = image.get();
-        // Cache the image here so that we can reuse it.
-        mImages[mCurrentTexture] = std::move(image);
-    }
-
-    mRE.bindExternalTextureImage(mTexName, *imageToRender);
-
-    // Wait for the new buffer to be ready.
-    return doFenceWaitLocked();
-}
-
-status_t BufferLayerConsumer::syncForReleaseLocked(const sp<Fence>& releaseFence) {
-    BLC_LOGV("syncForReleaseLocked");
-
-    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        if (mRE.useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
-            // TODO(alecmouri): fail further upstream if the fence is invalid
-            if (!releaseFence->isValid()) {
-                BLC_LOGE("syncForReleaseLocked: failed to flush RenderEngine");
-                return UNKNOWN_ERROR;
-            }
-            status_t err =
-                    addReleaseFenceLocked(mCurrentTexture, mCurrentTextureBuffer, releaseFence);
-            if (err != OK) {
-                BLC_LOGE("syncForReleaseLocked: error adding release fence: "
-                         "%s (%d)",
-                         strerror(-err), err);
-                return err;
-            }
-        }
-    }
-
-    return OK;
+    return mRE.bindExternalTextureBuffer(mTexName, mCurrentTextureBuffer, mCurrentFence, false);
 }
 
 void BufferLayerConsumer::getTransformMatrix(float mtx[16]) {
@@ -433,16 +354,29 @@
     return mCurrentApi;
 }
 
-sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
+sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp<Fence>* outFence) const {
     Mutex::Autolock lock(mMutex);
 
     if (outSlot != nullptr) {
         *outSlot = mCurrentTexture;
     }
 
+    if (outFence != nullptr) {
+        *outFence = mCurrentFence;
+    }
+
     return mCurrentTextureBuffer;
 }
 
+bool BufferLayerConsumer::getAndSetCurrentBufferCacheHint() {
+    Mutex::Autolock lock(mMutex);
+    bool useCache = mCurrentTextureBufferStaleForGpu;
+    // Set the staleness bit here, as this function is only called during a
+    // client composition path.
+    mCurrentTextureBufferStaleForGpu = true;
+    return useCache;
+}
+
 Rect BufferLayerConsumer::getCurrentCrop() const {
     Mutex::Autolock lock(mMutex);
     return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index ea46245..e2a6d2e 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -92,8 +92,7 @@
     // used to reject the newly acquired buffer.  It also does not bind the
     // RenderEngine texture until bindTextureImage is called.
     status_t updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
-                            bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber,
-                            const sp<Fence>& releaseFence);
+                            bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber);
 
     // See BufferLayerConsumer::bindTextureImageLocked().
     status_t bindTextureImage();
@@ -150,10 +149,16 @@
     // for use with bilinear filtering.
     void setFilteringEnabled(bool enabled);
 
+    // Sets mCurrentTextureBufferStaleForGpu to true to indicate that the
+    // buffer is now "stale" for GPU composition, and returns the old staleness
+    // bit as a caching hint.
+    bool getAndSetCurrentBufferCacheHint();
+
     // getCurrentBuffer returns the buffer associated with the current image.
     // When outSlot is not nullptr, the current buffer slot index is also
-    // returned.
-    sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr) const;
+    // returned. Simiarly, when outFence is not nullptr, the current output
+    // fence is returned.
+    sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr, sp<Fence>* outFence = nullptr) const;
 
     // getCurrentCrop returns the cropping rectangle of the current buffer.
     Rect getCurrentCrop() const;
@@ -206,8 +211,7 @@
     // completion of the method will instead be returned to the caller, so that
     // it may call releaseBufferLocked itself later.
     status_t updateAndReleaseLocked(const BufferItem& item,
-                                    PendingRelease* pendingRelease = nullptr,
-                                    const sp<Fence>& releaseFence = Fence::NO_FENCE);
+                                    PendingRelease* pendingRelease = nullptr);
 
     // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.
     // If the bind succeeds, this calls doFenceWait.
@@ -238,12 +242,6 @@
     // access the current texture buffer.
     status_t doFenceWaitLocked() const;
 
-    // syncForReleaseLocked performs the synchronization needed to release the
-    // current slot from RenderEngine.  If needed it will set the current
-    // slot's fence to guard against a producer accessing the buffer before
-    // the outstanding accesses have completed.
-    status_t syncForReleaseLocked(const sp<Fence>& releaseFence);
-
     // The default consumer usage flags that BufferLayerConsumer always sets on its
     // BufferQueue instance; these will be OR:d with any additional flags passed
     // from the BufferLayerConsumer user. In particular, BufferLayerConsumer will always
@@ -255,6 +253,10 @@
     // must track it separately in order to support the getCurrentBuffer method.
     sp<GraphicBuffer> mCurrentTextureBuffer;
 
+    // True if the buffer was used for the previous client composition frame,
+    // and false otherwise.
+    bool mCurrentTextureBufferStaleForGpu;
+
     // mCurrentCrop is the crop rectangle that applies to the current texture.
     // It gets set each time updateTexImage is called.
     Rect mCurrentCrop;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 42021d1..96c4992 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -14,13 +14,18 @@
  * limitations under the License.
  */
 
+#include <compositionengine/Display.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <system/window.h>
+
 #include "BufferQueueLayer.h"
 #include "LayerRejecter.h"
 
 #include "TimeStats/TimeStats.h"
 
-#include <system/window.h>
-
 namespace android {
 
 BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {}
@@ -190,22 +195,22 @@
     return mSidebandStreamChanged;
 }
 
-std::optional<Region> BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
     bool sidebandStreamChanged = true;
     if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
         // mSidebandStreamChanged was changed to false
         // replicated in LayerBE until FE/BE is ready to be synchronized
-        getBE().compositionInfo.hwc.sidebandStream = mConsumer->getSidebandStream();
-        if (getBE().compositionInfo.hwc.sidebandStream != nullptr) {
+        auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
+        layerCompositionState.sidebandStream = mConsumer->getSidebandStream();
+        if (layerCompositionState.sidebandStream != nullptr) {
             setTransactionFlags(eTransactionNeeded);
             mFlinger->setTransactionFlags(eTraversalNeeded);
         }
         recomputeVisibleRegions = true;
 
-        const State& s(getDrawingState());
-        return getTransform().transform(Region(Rect(s.active_legacy.w, s.active_legacy.h)));
+        return true;
     }
-    return {};
+    return false;
 }
 
 bool BufferQueueLayer::hasFrameUpdate() const {
@@ -220,8 +225,7 @@
     return mConsumer->bindTextureImage();
 }
 
-status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                                          const sp<Fence>& releaseFence) {
+status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) {
     // This boolean is used to make sure that SurfaceFlinger's shadow copy
     // of the buffer queue isn't modified when the buffer queue is returning
     // BufferItem's that weren't actually queued. This can happen in shared
@@ -232,12 +236,33 @@
                     getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
                     getTransformToDisplayInverse(), mFreezeGeometryUpdates);
 
-    const nsecs_t expectedPresentTime = mFlinger->mUseScheduler
-            ? mFlinger->mScheduler->mPrimaryDispSync->expectedPresentTime()
-            : mFlinger->mPrimaryDispSync->expectedPresentTime();
-    status_t updateResult =
-            mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh, &queuedBuffer,
-                                      mLastFrameNumberReceived, releaseFence);
+    nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime();
+
+    if (isRemovedFromCurrentState()) {
+        expectedPresentTime = 0;
+    }
+
+    // updateTexImage() below might drop the some buffers at the head of the queue if there is a
+    // buffer behind them which is timely to be presented. However this buffer may not be signaled
+    // yet. The code below makes sure that this wouldn't happen by setting maxFrameNumber to the
+    // last buffer that was signaled.
+    uint64_t lastSignaledFrameNumber = mLastFrameNumberReceived;
+    {
+        Mutex::Autolock lock(mQueueItemLock);
+        for (int i = 0; i < mQueueItems.size(); i++) {
+            bool fenceSignaled =
+                    mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+            if (!fenceSignaled) {
+                break;
+            }
+            lastSignaledFrameNumber = mQueueItems[i].mFrameNumber;
+        }
+    }
+    const uint64_t maxFrameNumberToAcquire =
+            std::min(mLastFrameNumberReceived.load(), lastSignaledFrameNumber);
+
+    status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh,
+                                                      &queuedBuffer, maxFrameNumberToAcquire);
     if (updateResult == BufferQueue::PRESENT_LATER) {
         // Producer doesn't want buffer to be displayed yet.  Signal a
         // layer update so we check again at the next opportunity.
@@ -306,9 +331,10 @@
 
 status_t BufferQueueLayer::updateActiveBuffer() {
     // update the active buffer
-    mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot);
-    getBE().compositionInfo.mBuffer = mActiveBuffer;
-    getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
+    mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence);
+    auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
+    layerCompositionState.buffer = mActiveBuffer;
+    layerCompositionState.bufferSlot = mActiveBufferSlot;
 
     if (mActiveBuffer == nullptr) {
         // this can only happen if the very first buffer was rejected.
@@ -317,6 +343,10 @@
     return NO_ERROR;
 }
 
+bool BufferQueueLayer::useCachedBufferForClientComposition() const {
+    return mConsumer->getAndSetCurrentBufferCacheHint();
+}
+
 status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) {
     mPreviousFrameNumber = mCurrentFrameNumber;
     mCurrentFrameNumber = mConsumer->getFrameNumber();
@@ -328,24 +358,28 @@
     return NO_ERROR;
 }
 
-void BufferQueueLayer::setHwcLayerBuffer(DisplayId displayId) {
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
-    auto& hwcLayer = hwcInfo.layer;
+void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    LOG_FATAL_IF(!outputLayer->getState.hwc);
+    auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
 
     uint32_t hwcSlot = 0;
     sp<GraphicBuffer> hwcBuffer;
-    hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);
+    (*outputLayer->editState().hwc)
+            .hwcBufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);
 
     auto acquireFence = mConsumer->getCurrentFence();
     auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
     if (error != HWC2::Error::None) {
-        ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
-              getBE().compositionInfo.mBuffer->handle, to_string(error).c_str(),
-              static_cast<int32_t>(error));
+        ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), mActiveBuffer->handle,
+              to_string(error).c_str(), static_cast<int32_t>(error));
     }
-    getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
-    getBE().compositionInfo.mBuffer = mActiveBuffer;
-    getBE().compositionInfo.hwc.fence = acquireFence;
+
+    auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
+    layerCompositionState.bufferSlot = mActiveBufferSlot;
+    layerCompositionState.buffer = mActiveBuffer;
+    layerCompositionState.acquireFence = acquireFence;
 }
 
 // -----------------------------------------------------------------------
@@ -355,7 +389,7 @@
 void BufferQueueLayer::fakeVsync() {
     mRefreshPending = false;
     bool ignored = false;
-    latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
+    latchBuffer(ignored, systemTime());
     usleep(16000);
     releasePendingBuffer(systemTime());
 }
@@ -363,8 +397,8 @@
 void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
     // Add this buffer from our internal queue tracker
     { // Autolock scope
-        // Report the requested present time to the Scheduler.
-        if (mFlinger->mUseScheduler) {
+        if (mFlinger->mUse90Hz && mFlinger->mUseSmart90ForVideo) {
+            // Report the requested present time to the Scheduler, if the feature is turned on.
             mFlinger->mScheduler->addFramePresentTimeForLayer(item.mTimestamp,
                                                               item.mIsAutoTimestamp, mName.c_str());
         }
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index d7c3f6a..fbb8c14 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -62,6 +62,9 @@
 public:
     bool fenceHasSignaled() const override;
 
+protected:
+    bool useCachedBufferForClientComposition() const override;
+
 private:
     nsecs_t getDesiredPresentTime() override;
     std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
@@ -81,20 +84,19 @@
     bool getAutoRefresh() const override;
     bool getSidebandStreamChanged() const override;
 
-    std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
+    bool latchSidebandStream(bool& recomputeVisibleRegions) override;
 
     bool hasFrameUpdate() const override;
 
     void setFilteringEnabled(bool enabled) override;
 
     status_t bindTextureImage() override;
-    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                            const sp<Fence>& releaseFence) override;
+    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
 
     status_t updateActiveBuffer() override;
     status_t updateFrameNumber(nsecs_t latchTime) override;
 
-    void setHwcLayerBuffer(DisplayId displayId) override;
+    void setHwcLayerBuffer(const sp<const DisplayDevice>& displayDevice) override;
 
     // -----------------------------------------------------------------------
     // Interface implementation for BufferLayerConsumer::ContentsChangedListener
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 044662c..f6b69eb 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -19,15 +19,19 @@
 #define LOG_TAG "BufferStateLayer"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include "BufferStateLayer.h"
-#include "ColorLayer.h"
+#include <limits>
 
-#include "TimeStats/TimeStats.h"
-
+#include <compositionengine/Display.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <private/gui/SyncFeatures.h>
 #include <renderengine/Image.h>
 
-#include <limits>
+#include "BufferStateLayer.h"
+#include "ColorLayer.h"
+#include "TimeStats/TimeStats.h"
 
 namespace android {
 
@@ -42,6 +46,7 @@
 
 BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) : BufferLayer(args) {
     mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
+    mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
 }
 BufferStateLayer::~BufferStateLayer() = default;
 
@@ -96,7 +101,8 @@
 bool BufferStateLayer::willPresentCurrentTransaction() const {
     // Returns true if the most recent Transaction applied to CurrentState will be presented.
     return getSidebandStreamChanged() || getAutoRefresh() ||
-            (mCurrentState.modified && mCurrentState.buffer != nullptr);
+            (mCurrentState.modified &&
+             (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr));
 }
 
 bool BufferStateLayer::getTransformToDisplayInverse() const {
@@ -192,7 +198,6 @@
         mReleasePreviousBuffer = true;
     }
 
-    mCurrentState.sequence++;
     mCurrentState.buffer = buffer;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -211,7 +216,6 @@
 
 bool BufferStateLayer::setDataspace(ui::Dataspace dataspace) {
     if (mCurrentState.dataspace == dataspace) return false;
-    mCurrentState.sequence++;
     mCurrentState.dataspace = dataspace;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -312,7 +316,7 @@
     // if the display frame is not defined, use the parent bounds as the buffer size.
     const auto& p = mDrawingParent.promote();
     if (p != nullptr) {
-        Rect parentBounds = Rect(p->computeBounds(Region()));
+        Rect parentBounds = Rect(p->getBounds(Region()));
         if (!parentBounds.isEmpty()) {
             return parentBounds;
         }
@@ -324,6 +328,18 @@
     }
     return Rect::INVALID_RECT;
 }
+
+FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) const {
+    const State& s(getDrawingState());
+    // for buffer state layers we use the display frame size as the buffer size.
+    if (getActiveWidth(s) < UINT32_MAX && getActiveHeight(s) < UINT32_MAX) {
+        return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s));
+    }
+
+    // if the display frame is not defined, use the parent bounds as the buffer size.
+    return parentBounds;
+}
+
 // -----------------------------------------------------------------------
 
 // -----------------------------------------------------------------------
@@ -420,25 +436,27 @@
     return mSidebandStreamChanged.load();
 }
 
-std::optional<Region> BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
     if (mSidebandStreamChanged.exchange(false)) {
         const State& s(getDrawingState());
         // mSidebandStreamChanged was true
-        // replicated in LayerBE until FE/BE is ready to be synchronized
-        getBE().compositionInfo.hwc.sidebandStream = s.sidebandStream;
-        if (getBE().compositionInfo.hwc.sidebandStream != nullptr) {
+        LOG_ALWAYS_FATAL_IF(!getCompositionLayer());
+        mSidebandStream = s.sidebandStream;
+        getCompositionLayer()->editState().frontEnd.sidebandStream = mSidebandStream;
+        if (mSidebandStream != nullptr) {
             setTransactionFlags(eTransactionNeeded);
             mFlinger->setTransactionFlags(eTraversalNeeded);
         }
         recomputeVisibleRegions = true;
 
-        return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
+        return true;
     }
-    return {};
+    return false;
 }
 
 bool BufferStateLayer::hasFrameUpdate() const {
-    return mCurrentStateModified && getCurrentState().buffer != nullptr;
+    const State& c(getCurrentState());
+    return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr);
 }
 
 void BufferStateLayer::setFilteringEnabled(bool enabled) {
@@ -450,53 +468,18 @@
     const State& s(getDrawingState());
     auto& engine(mFlinger->getRenderEngine());
 
-    engine.checkErrors();
-
-    // TODO(marissaw): once buffers are cached, don't create a new image everytime
-    mTextureImage = engine.createImage();
-
-    bool created =
-            mTextureImage->setNativeWindowBuffer(s.buffer->getNativeBuffer(),
-                                                 s.buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
-    if (!created) {
-        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
-              s.buffer->getWidth(), s.buffer->getHeight(), s.buffer->getStride(),
-              s.buffer->getUsage(), s.buffer->getPixelFormat());
-        engine.bindExternalTextureImage(mTextureName, *engine.createImage());
-        return NO_INIT;
-    }
-
-    engine.bindExternalTextureImage(mTextureName, *mTextureImage);
-
-    // Wait for the new buffer to be ready.
-    if (s.acquireFence->isValid()) {
-        if (SyncFeatures::getInstance().useWaitSync()) {
-            base::unique_fd fenceFd(s.acquireFence->dup());
-            if (fenceFd == -1) {
-                ALOGE("error dup'ing fence fd: %d", errno);
-                return -errno;
-            }
-            if (!engine.waitFence(std::move(fenceFd))) {
-                ALOGE("failed to wait on fence fd");
-                return UNKNOWN_ERROR;
-            }
-        } else {
-            status_t err = s.acquireFence->waitForever("BufferStateLayer::bindTextureImage");
-            if (err != NO_ERROR) {
-                ALOGE("error waiting for fence: %d", err);
-                return err;
-            }
-        }
-    }
-
-    return NO_ERROR;
+    return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence, false);
 }
 
-status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
-                                          const sp<Fence>& releaseFence) {
+status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime) {
     const State& s(getDrawingState());
 
     if (!s.buffer) {
+        if (s.bgColorLayer) {
+            for (auto& handle : mDrawingState.callbackHandles) {
+                handle->latchTime = latchTime;
+            }
+        }
         return NO_ERROR;
     }
 
@@ -530,59 +513,7 @@
         handle->latchTime = latchTime;
     }
 
-    // Handle sync fences
-    if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
-        // TODO(alecmouri): Fail somewhere upstream if the fence is invalid.
-        if (!releaseFence->isValid()) {
-            mFlinger->mTimeStats->onDestroy(layerID);
-            return UNKNOWN_ERROR;
-        }
-
-        // Check status of fences first because merging is expensive.
-        // Merging an invalid fence with any other fence results in an
-        // invalid fence.
-        auto currentStatus = s.acquireFence->getStatus();
-        if (currentStatus == Fence::Status::Invalid) {
-            ALOGE("Existing fence has invalid state");
-            mFlinger->mTimeStats->onDestroy(layerID);
-            return BAD_VALUE;
-        }
-
-        auto incomingStatus = releaseFence->getStatus();
-        if (incomingStatus == Fence::Status::Invalid) {
-            ALOGE("New fence has invalid state");
-            mDrawingState.acquireFence = releaseFence;
-            mFlinger->mTimeStats->onDestroy(layerID);
-            return BAD_VALUE;
-        }
-
-        // If both fences are signaled or both are unsignaled, we need to merge
-        // them to get an accurate timestamp.
-        if (currentStatus == incomingStatus) {
-            char fenceName[32] = {};
-            snprintf(fenceName, 32, "%.28s:%d", mName.string(), mFrameNumber);
-            sp<Fence> mergedFence =
-                    Fence::merge(fenceName, mDrawingState.acquireFence, releaseFence);
-            if (!mergedFence.get()) {
-                ALOGE("failed to merge release fences");
-                // synchronization is broken, the best we can do is hope fences
-                // signal in order so the new fence will act like a union
-                mDrawingState.acquireFence = releaseFence;
-                mFlinger->mTimeStats->onDestroy(layerID);
-                return BAD_VALUE;
-            }
-            mDrawingState.acquireFence = mergedFence;
-        } else if (incomingStatus == Fence::Status::Unsignaled) {
-            // If one fence has signaled and the other hasn't, the unsignaled
-            // fence will approximately correspond with the correct timestamp.
-            // There's a small race if both fences signal at about the same time
-            // and their statuses are retrieved with unfortunate timing. However,
-            // by this point, they will have both signaled and only the timestamp
-            // will be slightly off; any dependencies after this point will
-            // already have been met.
-            mDrawingState.acquireFence = releaseFence;
-        }
-    } else {
+    if (!SyncFeatures::getInstance().useNativeFenceSync()) {
         // Bind the new buffer to the GL texture.
         //
         // Older devices require the "implicit" synchronization provided
@@ -612,21 +543,29 @@
     }
 
     mActiveBuffer = s.buffer;
-    getBE().compositionInfo.mBuffer = mActiveBuffer;
-    getBE().compositionInfo.mBufferSlot = 0;
+    mActiveBufferFence = s.acquireFence;
+    auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
+    layerCompositionState.buffer = mActiveBuffer;
+    layerCompositionState.bufferSlot = 0;
 
     return NO_ERROR;
 }
 
+bool BufferStateLayer::useCachedBufferForClientComposition() const {
+    // TODO: Store a proper staleness bit to support EGLImage caching.
+    return false;
+}
+
 status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) {
     // TODO(marissaw): support frame history events
     mCurrentFrameNumber = mFrameNumber;
     return NO_ERROR;
 }
 
-void BufferStateLayer::setHwcLayerBuffer(DisplayId displayId) {
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
-    auto& hwcLayer = hwcInfo.layer;
+void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
+    auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
 
     const State& s(getDrawingState());
 
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 3f891d3..0b03f49 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -88,6 +88,7 @@
                                       uint64_t /*frameNumber*/) override {}
 
     Rect getBufferSize(const State& s) const override;
+    FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
     // -----------------------------------------------------------------------
 
     // -----------------------------------------------------------------------
@@ -95,6 +96,9 @@
     // -----------------------------------------------------------------------
     bool fenceHasSignaled() const override;
 
+protected:
+    bool useCachedBufferForClientComposition() const override;
+
 private:
     nsecs_t getDesiredPresentTime() override;
     std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
@@ -114,20 +118,19 @@
     bool getAutoRefresh() const override;
     bool getSidebandStreamChanged() const override;
 
-    std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
+    bool latchSidebandStream(bool& recomputeVisibleRegions) override;
 
     bool hasFrameUpdate() const override;
 
     void setFilteringEnabled(bool enabled) override;
 
     status_t bindTextureImage() override;
-    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                            const sp<Fence>& releaseFence) override;
+    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
 
     status_t updateActiveBuffer() override;
     status_t updateFrameNumber(nsecs_t latchTime) override;
 
-    void setHwcLayerBuffer(DisplayId displayId) override;
+    void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
 
 private:
     void onFirstRef() override;
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 0ca3759..e54b460 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -17,7 +17,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <binder/PermissionCache.h>
 #include <binder/IPCThreadState.h>
 
 #include <private/android_filesystem_config.h>
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index b4e9d17..9ea0a46 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -23,8 +23,12 @@
 #include <sys/types.h>
 
 #include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
 #include <compositionengine/Layer.h>
 #include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <renderengine/RenderEngine.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/Errors.h>
@@ -44,28 +48,14 @@
 
 ColorLayer::~ColorLayer() = default;
 
-void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */,
-                        bool useIdentityTransform) {
-    half4 color = getColor();
-    if (color.a > 0) {
-        renderengine::Mesh mesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2);
-        computeGeometry(renderArea, mesh, useIdentityTransform);
-        auto& engine(mFlinger->getRenderEngine());
-
-        Rect win{computeBounds()};
-
-        const auto roundedCornerState = getRoundedCornerState();
-        const auto cropRect = roundedCornerState.cropRect;
-        setupRoundedCornersCropCoordinates(win, cropRect);
-
-        engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */,
-                                  true /* disableTexture */, color, roundedCornerState.radius);
-
-        engine.setSourceDataSpace(mCurrentDataSpace);
-        engine.setupCornerRadiusCropSize(cropRect.getWidth(), cropRect.getHeight());
-        engine.drawMesh(mesh);
-        engine.disableBlending();
-    }
+bool ColorLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+                                    bool useIdentityTransform, Region& clearRegion,
+                                    renderengine::LayerSettings& layer) {
+    Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, layer);
+    half4 color(getColor());
+    half3 solidColor(color.r, color.g, color.b);
+    layer.source.solidColor = solidColor;
+    return true;
 }
 
 bool ColorLayer::isVisible() const {
@@ -87,30 +77,36 @@
     return true;
 }
 
-void ColorLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
-                                 const Rect& viewport, int32_t /* supportedPerFrameMetadata */) {
-    RETURN_IF_NO_HWC_LAYER(displayId);
+void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display,
+                                 const ui::Transform& transform, const Rect& viewport,
+                                 int32_t /* supportedPerFrameMetadata */) {
+    RETURN_IF_NO_HWC_LAYER(display);
 
     Region visible = transform.transform(visibleRegion.intersect(viewport));
 
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
-    auto& hwcLayer = hwcInfo.layer;
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
+
+    auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
+
     auto error = hwcLayer->setVisibleRegion(visible);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
               to_string(error).c_str(), static_cast<int32_t>(error));
         visible.dump(LOG_TAG);
     }
-    getBE().compositionInfo.hwc.visibleRegion = visible;
+    outputLayer->editState().visibleRegion = visible;
 
-    setCompositionType(displayId, HWC2::Composition::SolidColor);
+    setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR);
 
     error = hwcLayer->setDataspace(mCurrentDataSpace);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
-    getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
+
+    auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
+    layerCompositionState.dataspace = mCurrentDataSpace;
 
     half4 color = getColor();
     error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
@@ -120,9 +116,9 @@
         ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(),
               static_cast<int32_t>(error));
     }
-    getBE().compositionInfo.hwc.color = { static_cast<uint8_t>(std::round(255.0f * color.r)),
-                                      static_cast<uint8_t>(std::round(255.0f * color.g)),
-                                      static_cast<uint8_t>(std::round(255.0f * color.b)), 255 };
+    layerCompositionState.color = {static_cast<uint8_t>(std::round(255.0f * color.r)),
+                                   static_cast<uint8_t>(std::round(255.0f * color.g)),
+                                   static_cast<uint8_t>(std::round(255.0f * color.b)), 255};
 
     // Clear out the transform, because it doesn't make sense absent a source buffer
     error = hwcLayer->setTransform(HWC2::Transform::None);
@@ -130,14 +126,14 @@
         ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(),
               static_cast<int32_t>(error));
     }
-    getBE().compositionInfo.hwc.transform = HWC2::Transform::None;
+    outputLayer->editState().bufferTransform = static_cast<Hwc2::Transform>(0);
 
     error = hwcLayer->setColorTransform(getColorTransform());
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
                 to_string(error).c_str(), static_cast<int32_t>(error));
     }
-    getBE().compositionInfo.hwc.colorTransform = getColorTransform();
+    layerCompositionState.colorTransform = getColorTransform();
 
     error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
     if (error != HWC2::Error::None) {
@@ -145,7 +141,7 @@
               to_string(error).c_str(), static_cast<int32_t>(error));
         surfaceDamageRegion.dump(LOG_TAG);
     }
-    getBE().compositionInfo.hwc.surfaceDamage = surfaceDamageRegion;
+    layerCompositionState.surfaceDamage = surfaceDamageRegion;
 }
 
 std::shared_ptr<compositionengine::Layer> ColorLayer::getCompositionLayer() const {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 3b98e8c..df0adac 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -31,19 +31,20 @@
     std::shared_ptr<compositionengine::Layer> getCompositionLayer() const override;
 
     virtual const char* getTypeId() const { return "ColorLayer"; }
-    virtual void onDraw(const RenderArea& renderArea, const Region& clip,
-                        bool useIdentityTransform);
     bool isVisible() const override;
 
     bool setColor(const half3& color) override;
 
-    void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
-                         int32_t supportedPerFrameMetadata) override;
+    void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
+                         const Rect& viewport, int32_t supportedPerFrameMetadata) override;
 
     bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
 
 protected:
     FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
+    virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+                                    bool useIdentityTransform, Region& clearRegion,
+                                    renderengine::LayerSettings& layer);
 
 private:
     std::shared_ptr<compositionengine::Layer> mCompositionLayer;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index ce6b06c..e86d35d 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -5,6 +5,7 @@
         "-DLOG_TAG=\"CompositionEngine\"",
     ],
     shared_libs: [
+        "android.frameworks.vr.composer@1.0",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
@@ -28,6 +29,9 @@
         "libtrace_proto",
     ],
     header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+        "android.hardware.graphics.composer@2.3-command-buffer",
         "libsurfaceflinger_headers",
     ],
 }
@@ -43,9 +47,11 @@
         "src/DumpHelpers.cpp",
         "src/HwcBufferCache.cpp",
         "src/Layer.cpp",
+        "src/LayerCompositionState.cpp",
         "src/Output.cpp",
         "src/OutputCompositionState.cpp",
         "src/OutputLayer.cpp",
+        "src/OutputLayerCompositionState.cpp",
         "src/RenderSurface.cpp",
     ],
     local_include_dirs: ["include"],
@@ -85,6 +91,7 @@
         "tests/DisplayTest.cpp",
         "tests/HwcBufferCacheTest.cpp",
         "tests/LayerTest.cpp",
+        "tests/MockHWC2.cpp",
         "tests/MockHWComposer.cpp",
         "tests/OutputTest.cpp",
         "tests/OutputLayerTest.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
index 29a7dea..8cb9203 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <cstdint>
+#include <string>
 
 #include <utils/StrongPointer.h>
 
@@ -29,6 +30,10 @@
 class Display;
 class LayerFE;
 
+namespace impl {
+struct LayerCompositionState;
+} // namespace impl
+
 /**
  * A layer contains the output-independent composition state for a front-end
  * Layer
@@ -40,6 +45,21 @@
     // Gets the front-end interface for this layer.  Can return nullptr if the
     // front-end layer no longer exists.
     virtual sp<LayerFE> getLayerFE() const = 0;
+
+    using CompositionState = impl::LayerCompositionState;
+
+    // Gets the raw composition state data for the layer
+    // TODO(lpique): Make this protected once it is only internally called.
+    virtual const CompositionState& getState() const = 0;
+
+    // Allows mutable access to the raw composition state data for the layer.
+    // This is meant to be used by the various functions that are part of the
+    // composition process.
+    // TODO(lpique): Make this protected once it is only internally called.
+    virtual CompositionState& editState() = 0;
+
+    // Debugging
+    virtual void dump(std::string& result) const = 0;
 };
 
 } // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
new file mode 100644
index 0000000..785a6d7
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -0,0 +1,96 @@
+/*
+ * 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 <cstdint>
+
+#include <gui/BufferQueue.h>
+#include <gui/HdrMetadata.h>
+#include <math/mat4.h>
+#include <ui/FloatRect.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+#include "DisplayHardware/ComposerHal.h"
+
+namespace android::compositionengine {
+
+/*
+ * Used by LayerFE::getCompositionState
+ */
+struct LayerFECompositionState {
+    // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
+    // value recomputed / set every frame.
+    Region geomVisibleRegion;
+
+    /*
+     * Presentation
+     */
+
+    // The blend mode for this layer
+    Hwc2::IComposerClient::BlendMode blendMode{Hwc2::IComposerClient::BlendMode::INVALID};
+
+    // The alpha value for this layer
+    float alpha{1.f};
+
+    /*
+     * Extra metadata
+     */
+
+    // The type for this layer
+    int type{0};
+
+    // The appId for this layer
+    int appId{0};
+
+    /*
+     * Per-frame content
+     */
+
+    // The type of composition for this layer
+    Hwc2::IComposerClient::Composition compositionType{Hwc2::IComposerClient::Composition::INVALID};
+
+    // The buffer and related state
+    sp<GraphicBuffer> buffer;
+    int bufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
+    sp<Fence> acquireFence;
+    Region surfaceDamage;
+
+    // The handle to use for a sideband stream for this layer
+    sp<NativeHandle> sidebandStream;
+
+    // The color for this layer
+    Hwc2::IComposerClient::Color color;
+
+    /*
+     * Per-frame presentation state
+     */
+
+    // The dataspace for this layer
+    ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+
+    // The metadata for this layer
+    HdrMetadata hdrMetadata;
+
+    // The color transform
+    mat4 colorTransform;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index a7ab472..54e6bd6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <cstdint>
+#include <optional>
 #include <string>
 
 #include <math/mat4.h>
@@ -25,6 +26,8 @@
 #include <ui/Transform.h>
 #include <utils/StrongPointer.h>
 
+#include "DisplayHardware/DisplayIdentification.h"
+
 namespace android::compositionengine {
 
 class DisplayColorProfile;
@@ -97,10 +100,9 @@
     // TODO(lpique): Make this protected once it is only internally called.
     virtual OutputCompositionState& editState() = 0;
 
-    // Gets the physical space dirty region. If repaintEverything is true, this
-    // will be the full display bounds. Internally the dirty region is stored in
-    // logical (aka layer stack) space.
-    virtual Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const = 0;
+    // Gets the dirty region in layer stack space.
+    // If repaintEverything is true, this will be the full display bounds.
+    virtual Region getDirtyRegion(bool repaintEverything) const = 0;
 
     // Tests whether a given layerStackId belongs in this output.
     // A layer belongs to the output if its layerStackId matches the of the output layerStackId,
@@ -118,7 +120,8 @@
     // Gets the OutputLayer corresponding to the input Layer instance from the
     // current ordered set of output layers. If there is no such layer, a new
     // one is created and returned.
-    virtual std::unique_ptr<OutputLayer> getOrCreateOutputLayer(std::shared_ptr<Layer>,
+    virtual std::unique_ptr<OutputLayer> getOrCreateOutputLayer(std::optional<DisplayId>,
+                                                                std::shared_ptr<Layer>,
                                                                 sp<LayerFE>) = 0;
 
     // Sets the new ordered set of output layers for this output
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index 4b8ef38..e7a17c4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -16,14 +16,26 @@
 
 #pragma once
 
+#include <optional>
+#include <string>
+
 #include <utils/StrongPointer.h>
 
-namespace android::compositionengine {
+#include "DisplayHardware/DisplayIdentification.h"
 
+namespace android {
+
+namespace compositionengine {
+
+class CompositionEngine;
 class Output;
 class Layer;
 class LayerFE;
 
+namespace impl {
+struct OutputLayerCompositionState;
+} // namespace impl
+
 /**
  * An output layer contains the output-dependent composition state for a layer
  */
@@ -39,6 +51,22 @@
 
     // Gets the front-end layer interface this output layer represents
     virtual LayerFE& getLayerFE() const = 0;
+
+    using CompositionState = compositionengine::impl::OutputLayerCompositionState;
+
+    // Gets the raw composition state data for the layer
+    // TODO(lpique): Make this protected once it is only internally called.
+    virtual const CompositionState& getState() const = 0;
+
+    // Allows mutable access to the raw composition state data for the layer.
+    // This is meant to be used by the various functions that are part of the
+    // composition process.
+    // TODO(lpique): Make this protected once it is only internally called.
+    virtual CompositionState& editState() = 0;
+
+    // Debugging
+    virtual void dump(std::string& result) const = 0;
 };
 
-} // namespace android::compositionengine
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index dd01b05..e69b99f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -29,8 +29,6 @@
 
 class GraphicBuffer;
 
-struct CompositionInfo;
-
 namespace compositionengine {
 
 /**
@@ -70,21 +68,18 @@
     virtual status_t beginFrame(bool mustRecompose) = 0;
 
     // Prepares the frame for rendering
-    virtual status_t prepareFrame(std::vector<CompositionInfo>& compositionData) = 0;
+    virtual status_t prepareFrame() = 0;
 
     // Allocates a buffer as scratch space for GPU composition
-    virtual sp<GraphicBuffer> dequeueBuffer() = 0;
+    virtual sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) = 0;
 
-    // Queues the drawn buffer for consumption by HWC
-    virtual void queueBuffer() = 0;
+    // Queues the drawn buffer for consumption by HWC. readyFence is the fence
+    // which will fire when the buffer is ready for consumption.
+    virtual void queueBuffer(base::unique_fd&& readyFence) = 0;
 
     // Called after the HWC calls are made to present the display
     virtual void onPresentDisplayCompleted() = 0;
 
-    // Marks the current buffer has finished, so that it can be presented and
-    // swapped out
-    virtual void finishBuffer() = 0;
-
     // Called to set the viewport and projection state for rendering into this
     // surface
     virtual void setViewportAndProjection() = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
index 631351b..3e56b21 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
@@ -19,6 +19,7 @@
 #include <memory>
 
 #include <compositionengine/Layer.h>
+#include <compositionengine/impl/LayerCompositionState.h>
 #include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
 
@@ -40,9 +41,16 @@
 
     sp<LayerFE> getLayerFE() const override;
 
+    const LayerCompositionState& getState() const override;
+    LayerCompositionState& editState() override;
+
+    void dump(std::string& result) const override;
+
 private:
     const compositionengine::CompositionEngine& mCompositionEngine;
     const wp<LayerFE> mLayerFE;
+
+    LayerCompositionState mState;
 };
 
 std::shared_ptr<compositionengine::Layer> createLayer(const compositionengine::CompositionEngine&,
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
new file mode 100644
index 0000000..67bea4b
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
@@ -0,0 +1,47 @@
+/*
+ * 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 <cstdint>
+#include <string>
+
+#include <compositionengine/LayerFECompositionState.h>
+#include <renderengine/Mesh.h>
+
+namespace android {
+
+namespace compositionengine::impl {
+
+struct LayerCompositionState {
+    /*
+     * State intended to be set by LayerFE::getCompositionState
+     */
+
+    LayerFECompositionState frontEnd;
+
+    /*
+     * RE state
+     */
+
+    renderengine::Mesh reMesh{renderengine::Mesh::TRIANGLE_FAN, 4, 2, 2};
+
+    // Debugging
+    void dump(std::string& result) const;
+};
+
+} // namespace compositionengine::impl
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index d876c03..b1d1f42 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -61,13 +61,14 @@
     const OutputCompositionState& getState() const override;
     OutputCompositionState& editState() override;
 
-    Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const override;
+    Region getDirtyRegion(bool repaintEverything) const override;
     bool belongsInOutput(uint32_t, bool) const override;
 
     compositionengine::OutputLayer* getOutputLayerForLayer(
             compositionengine::Layer*) const override;
     std::unique_ptr<compositionengine::OutputLayer> getOrCreateOutputLayer(
-            std::shared_ptr<compositionengine::Layer>, sp<LayerFE>) override;
+            std::optional<DisplayId>, std::shared_ptr<compositionengine::Layer>,
+            sp<LayerFE>) override;
     void setOutputLayersOrderedByZ(OutputLayers&&) override;
     const OutputLayers& getOutputLayersOrderedByZ() const override;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index f3d0258..d8f0cdd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -17,8 +17,12 @@
 #pragma once
 
 #include <memory>
+#include <string>
 
 #include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
+
+#include "DisplayHardware/DisplayIdentification.h"
 
 namespace android::compositionengine::impl {
 
@@ -28,18 +32,27 @@
                 sp<compositionengine::LayerFE>);
     ~OutputLayer() override;
 
+    void initialize(const CompositionEngine&, std::optional<DisplayId>);
+
     const compositionengine::Output& getOutput() const override;
     compositionengine::Layer& getLayer() const override;
     compositionengine::LayerFE& getLayerFE() const override;
 
+    const OutputLayerCompositionState& getState() const override;
+    OutputLayerCompositionState& editState() override;
+
+    void dump(std::string& result) const override;
+
 private:
     const compositionengine::Output& mOutput;
     std::shared_ptr<compositionengine::Layer> mLayer;
     sp<compositionengine::LayerFE> mLayerFE;
+
+    OutputLayerCompositionState mState;
 };
 
 std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
-        const compositionengine::Output&, std::shared_ptr<compositionengine::Layer>,
-        sp<compositionengine::LayerFE>);
+        const CompositionEngine&, std::optional<DisplayId>, const compositionengine::Output&,
+        std::shared_ptr<compositionengine::Layer>, sp<compositionengine::LayerFE>);
 
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
new file mode 100644
index 0000000..b78e9e0
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -0,0 +1,91 @@
+/*
+ * 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 <cstdint>
+#include <optional>
+#include <string>
+
+#include <compositionengine/impl/HwcBufferCache.h>
+#include <renderengine/Mesh.h>
+#include <ui/FloatRect.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#include "DisplayHardware/ComposerHal.h"
+
+namespace HWC2 {
+class Layer;
+} // namespace HWC2
+
+namespace android {
+
+class HWComposer;
+
+namespace compositionengine::impl {
+
+struct OutputLayerCompositionState {
+    // The region of this layer which is visible on this output
+    Region visibleRegion;
+
+    // If true, client composition will be used on this output
+    bool forceClientComposition{false};
+
+    // If true, when doing client composition, the target may need to be cleared
+    bool clearClientTarget{false};
+
+    // The display frame for this layer on this output
+    Rect displayFrame;
+
+    // The source crop for this layer on this output
+    FloatRect sourceCrop;
+
+    // The buffer transform to use for this layer o on this output.
+    Hwc2::Transform bufferTransform{static_cast<Hwc2::Transform>(0)};
+
+    // The Z order index of this layer on this output
+    uint32_t z;
+
+    /*
+     * HWC state
+     */
+
+    struct Hwc {
+        explicit Hwc(std::shared_ptr<HWC2::Layer> hwcLayer) : hwcLayer(hwcLayer) {}
+
+        // The HWC Layer backing this layer
+        std::shared_ptr<HWC2::Layer> hwcLayer;
+
+        // The HWC composition type for this layer
+        Hwc2::IComposerClient::Composition hwcCompositionType{
+                Hwc2::IComposerClient::Composition::INVALID};
+
+        // The buffer cache for this layer. This is used to lower the
+        // cost of sending reused buffers to the HWC.
+        HwcBufferCache hwcBufferCache;
+    };
+
+    // The HWC state is optional, and is only set up if there is any potential
+    // HWC acceleration possible.
+    std::optional<Hwc> hwc;
+
+    // Debugging
+    void dump(std::string& result) const;
+};
+
+} // namespace compositionengine::impl
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 0489310..3c79084 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -51,11 +51,10 @@
     void setDisplaySize(const ui::Size&) override;
     void setProtected(bool useProtected) override;
     status_t beginFrame(bool mustRecompose) override;
-    status_t prepareFrame(std::vector<CompositionInfo>& compositionData) override;
-    sp<GraphicBuffer> dequeueBuffer() override;
-    void queueBuffer() override;
+    status_t prepareFrame() override;
+    sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override;
+    void queueBuffer(base::unique_fd&& readyFence) override;
     void onPresentDisplayCompleted() override;
-    void finishBuffer() override;
     void setViewportAndProjection() override;
     void flip() override;
 
@@ -77,9 +76,6 @@
     const sp<ANativeWindow> mNativeWindow;
     // Current buffer being rendered into
     sp<GraphicBuffer> mGraphicBuffer;
-    // File descriptor indicating that mGraphicBuffer is ready for display, i.e.
-    // that drawing to the buffer is now complete.
-    base::unique_fd mBufferReady;
     const sp<DisplaySurface> mDisplaySurface;
     ui::Size mSize;
     std::uint32_t mPageFlipCount{0};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
index a7cc08e..cce3b97 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
@@ -18,6 +18,7 @@
 
 #include <compositionengine/Layer.h>
 #include <compositionengine/LayerFE.h>
+#include <compositionengine/impl/LayerCompositionState.h>
 #include <gmock/gmock.h>
 
 namespace android::compositionengine::mock {
@@ -28,6 +29,11 @@
     virtual ~Layer();
 
     MOCK_CONST_METHOD0(getLayerFE, sp<LayerFE>());
+
+    MOCK_CONST_METHOD0(getState, const CompositionState&());
+    MOCK_METHOD0(editState, CompositionState&());
+
+    MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
 } // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index e79a44c..d0e7b19 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -56,14 +56,14 @@
     MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
     MOCK_METHOD0(editState, OutputCompositionState&());
 
-    MOCK_CONST_METHOD1(getPhysicalSpaceDirtyRegion, Region(bool));
+    MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
     MOCK_CONST_METHOD2(belongsInOutput, bool(uint32_t, bool));
 
     MOCK_CONST_METHOD1(getOutputLayerForLayer,
                        compositionengine::OutputLayer*(compositionengine::Layer*));
-    MOCK_METHOD2(getOrCreateOutputLayer,
+    MOCK_METHOD3(getOrCreateOutputLayer,
                  std::unique_ptr<compositionengine::OutputLayer>(
-                         std::shared_ptr<compositionengine::Layer>,
+                         std::optional<DisplayId>, std::shared_ptr<compositionengine::Layer>,
                          sp<compositionengine::LayerFE>));
     MOCK_METHOD1(setOutputLayersOrderedByZ, void(OutputLayers&&));
     MOCK_CONST_METHOD0(getOutputLayersOrderedByZ, OutputLayers&());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index f5e5026..54c7407 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -16,10 +16,12 @@
 
 #pragma once
 
+#include <compositionengine/CompositionEngine.h>
 #include <compositionengine/Layer.h>
 #include <compositionengine/LayerFE.h>
 #include <compositionengine/Output.h>
 #include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <gmock/gmock.h>
 
 namespace android::compositionengine::mock {
@@ -32,6 +34,11 @@
     MOCK_CONST_METHOD0(getOutput, const compositionengine::Output&());
     MOCK_CONST_METHOD0(getLayer, compositionengine::Layer&());
     MOCK_CONST_METHOD0(getLayerFE, compositionengine::LayerFE&());
+
+    MOCK_CONST_METHOD0(getState, const impl::OutputLayerCompositionState&());
+    MOCK_METHOD0(editState, impl::OutputLayerCompositionState&());
+
+    MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
 } // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index 2269e57..1562f58 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -20,7 +20,6 @@
 #include <gmock/gmock.h>
 #include <ui/GraphicBuffer.h>
 
-#include "LayerBE.h"
 
 namespace android::compositionengine::mock {
 
@@ -37,11 +36,10 @@
     MOCK_METHOD1(setProtected, void(bool));
     MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
     MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
-    MOCK_METHOD1(prepareFrame, status_t(std::vector<CompositionInfo>& compositionData));
-    MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>());
-    MOCK_METHOD0(queueBuffer, void());
+    MOCK_METHOD0(prepareFrame, status_t());
+    MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*));
+    MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
     MOCK_METHOD0(onPresentDisplayCompleted, void());
-    MOCK_METHOD0(finishBuffer, void());
     MOCK_METHOD0(setViewportAndProjection, void());
     MOCK_METHOD0(flip, void());
     MOCK_CONST_METHOD1(dump, void(std::string& result));
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
index 6e6f3c0..130ab1d 100644
--- a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
@@ -303,7 +303,7 @@
     }
 
     // add all known HDR combinations
-    for (auto intent : sHdrRenderIntents) {
+    for (auto intent : hdrRenderIntents) {
         for (auto mode : sHdrColorModes) {
             addColorMode(hwcColorModes, mode, intent);
         }
diff --git a/services/surfaceflinger/CompositionEngine/src/Layer.cpp b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
index aaa758e..109e9f8 100644
--- a/services/surfaceflinger/CompositionEngine/src/Layer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/stringprintf.h>
 #include <compositionengine/CompositionEngine.h>
 #include <compositionengine/LayerCreationArgs.h>
 #include <compositionengine/LayerFE.h>
@@ -42,5 +43,18 @@
     return mLayerFE.promote();
 }
 
+const LayerCompositionState& Layer::getState() const {
+    return mState;
+}
+
+LayerCompositionState& Layer::editState() {
+    return mState;
+}
+
+void Layer::dump(std::string& out) const {
+    android::base::StringAppendF(&out, "     Layer %p\n", this);
+    mState.dump(out);
+}
+
 } // namespace impl
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
new file mode 100644
index 0000000..517b641
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 <android-base/stringprintf.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+
+namespace android::compositionengine::impl {
+
+namespace {
+
+using android::compositionengine::impl::dumpVal;
+
+void dumpVal(std::string& out, const char* name, Hwc2::IComposerClient::Color value) {
+    using android::base::StringAppendF;
+    StringAppendF(&out, "%s=[%d %d %d] ", name, value.r, value.g, value.b);
+}
+
+void dumpFrontEnd(std::string& out, const LayerFECompositionState& state) {
+    out.append("      ");
+    dumpVal(out, "blend", toString(state.blendMode), state.blendMode);
+    dumpVal(out, "alpha", state.alpha);
+
+    out.append("\n      ");
+    dumpVal(out, "type", state.type);
+    dumpVal(out, "appId", state.appId);
+
+    dumpVal(out, "composition type", toString(state.compositionType), state.compositionType);
+
+    out.append("\n      buffer: ");
+    dumpVal(out, "buffer", state.buffer.get());
+    dumpVal(out, "slot", state.bufferSlot);
+
+    out.append("\n      ");
+    dumpVal(out, "sideband stream", state.sidebandStream.get());
+
+    out.append("\n      ");
+    dumpVal(out, "color", state.color);
+
+    out.append("\n      ");
+    dumpVal(out, "dataspace", toString(state.dataspace), state.dataspace);
+    dumpVal(out, "hdr metadata types", state.hdrMetadata.validTypes);
+    dumpVal(out, "colorTransform", state.colorTransform);
+
+    out.append("\n");
+}
+
+} // namespace
+
+void LayerCompositionState::dump(std::string& out) const {
+    out.append("      frontend:\n");
+    dumpFrontEnd(out, frontEnd);
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 6d5147d..ad4c7bf 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -90,13 +90,25 @@
 
 void Output::setColorTransform(const mat4& transform) {
     const bool isIdentity = (transform == mat4());
-
-    mState.colorTransform =
+    const auto newColorTransform =
             isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+
+    if (mState.colorTransform == newColorTransform) {
+        return;
+    }
+
+    mState.colorTransform = newColorTransform;
+
+    dirtyEntireOutput();
 }
 
 void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
                           ui::RenderIntent renderIntent) {
+    if (mState.colorMode == mode && mState.dataspace == dataspace &&
+        mState.renderIntent == renderIntent) {
+        return;
+    }
+
     mState.colorMode = mode;
     mState.dataspace = dataspace;
     mState.renderIntent = renderIntent;
@@ -106,6 +118,8 @@
     ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)",
           decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
           renderIntent);
+
+    dirtyEntireOutput();
 }
 
 void Output::dump(std::string& out) const {
@@ -132,6 +146,14 @@
     } else {
         out.append("    No render surface!\n");
     }
+
+    out.append("\n   %d Layers", mOutputLayersOrderedByZ.size());
+    for (const auto& outputLayer : mOutputLayersOrderedByZ) {
+        if (!outputLayer) {
+            continue;
+        }
+        outputLayer->dump(out);
+    }
 }
 
 compositionengine::DisplayColorProfile* Output::getDisplayColorProfile() const {
@@ -170,13 +192,10 @@
     return mState;
 }
 
-Region Output::getPhysicalSpaceDirtyRegion(bool repaintEverything) const {
-    Region dirty;
-    if (repaintEverything) {
-        dirty.set(mState.bounds);
-    } else {
-        dirty = mState.transform.transform(mState.dirtyRegion);
-        dirty.andSelf(mState.bounds);
+Region Output::getDirtyRegion(bool repaintEverything) const {
+    Region dirty(mState.viewport);
+    if (!repaintEverything) {
+        dirty.andSelf(mState.dirtyRegion);
     }
     return dirty;
 }
@@ -198,13 +217,14 @@
 }
 
 std::unique_ptr<compositionengine::OutputLayer> Output::getOrCreateOutputLayer(
-        std::shared_ptr<compositionengine::Layer> layer, sp<compositionengine::LayerFE> layerFE) {
+        std::optional<DisplayId> displayId, std::shared_ptr<compositionengine::Layer> layer,
+        sp<compositionengine::LayerFE> layerFE) {
     for (auto& outputLayer : mOutputLayersOrderedByZ) {
         if (outputLayer && &outputLayer->getLayer() == layer.get()) {
             return std::move(outputLayer);
         }
     }
-    return createOutputLayer(*this, layer, layerFE);
+    return createOutputLayer(mCompositionEngine, displayId, *this, layer, layerFE);
 }
 
 void Output::setOutputLayersOrderedByZ(OutputLayers&& layers) {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index e95f3a6..10da49d 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -14,11 +14,15 @@
  * limitations under the License.
  */
 
+#include <android-base/stringprintf.h>
+#include <compositionengine/CompositionEngine.h>
 #include <compositionengine/Layer.h>
 #include <compositionengine/LayerFE.h>
 #include <compositionengine/Output.h>
 #include <compositionengine/impl/OutputLayer.h>
 
+#include "DisplayHardware/HWComposer.h"
+
 namespace android::compositionengine {
 
 OutputLayer::~OutputLayer() = default;
@@ -26,9 +30,12 @@
 namespace impl {
 
 std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
-        const compositionengine::Output& display, std::shared_ptr<compositionengine::Layer> layer,
+        const CompositionEngine& compositionEngine, std::optional<DisplayId> displayId,
+        const compositionengine::Output& output, std::shared_ptr<compositionengine::Layer> layer,
         sp<compositionengine::LayerFE> layerFE) {
-    return std::make_unique<OutputLayer>(display, layer, layerFE);
+    auto result = std::make_unique<OutputLayer>(output, layer, layerFE);
+    result->initialize(compositionEngine, displayId);
+    return result;
 }
 
 OutputLayer::OutputLayer(const Output& output, std::shared_ptr<Layer> layer, sp<LayerFE> layerFE)
@@ -36,6 +43,20 @@
 
 OutputLayer::~OutputLayer() = default;
 
+void OutputLayer::initialize(const CompositionEngine& compositionEngine,
+                             std::optional<DisplayId> displayId) {
+    if (!displayId) {
+        return;
+    }
+
+    auto& hwc = compositionEngine.getHwComposer();
+
+    mState.hwc.emplace(std::shared_ptr<HWC2::Layer>(hwc.createLayer(*displayId),
+                                                    [&hwc, displayId](HWC2::Layer* layer) {
+                                                        hwc.destroyLayer(*displayId, layer);
+                                                    }));
+}
+
 const compositionengine::Output& OutputLayer::getOutput() const {
     return mOutput;
 }
@@ -48,5 +69,20 @@
     return *mLayerFE;
 }
 
+const OutputLayerCompositionState& OutputLayer::getState() const {
+    return mState;
+}
+
+OutputLayerCompositionState& OutputLayer::editState() {
+    return mState;
+}
+
+void OutputLayer::dump(std::string& out) const {
+    using android::base::StringAppendF;
+
+    StringAppendF(&out, "     Output Layer %p\n", this);
+    mState.dump(out);
+}
+
 } // namespace impl
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
new file mode 100644
index 0000000..10f27b8
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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 <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
+
+#include "DisplayHardware/HWC2.h"
+
+namespace android::compositionengine::impl {
+
+namespace {
+
+void dumpHwc(const OutputLayerCompositionState::Hwc& hwc, std::string& out) {
+    out.append("\n      hwc: ");
+
+    if (hwc.hwcLayer == nullptr) {
+        out.append("No layer ");
+    } else {
+        dumpHex(out, "layer", hwc.hwcLayer->getId());
+    }
+
+    dumpVal(out, "composition", toString(hwc.hwcCompositionType), hwc.hwcCompositionType);
+}
+
+} // namespace
+
+void OutputLayerCompositionState::dump(std::string& out) const {
+    out.append("      ");
+    dumpVal(out, "visibleRegion", visibleRegion);
+
+    out.append("      ");
+    dumpVal(out, "forceClientComposition", forceClientComposition);
+    dumpVal(out, "clearClientTarget", clearClientTarget);
+    dumpVal(out, "displayFrame", displayFrame);
+    dumpVal(out, "sourceCrop", sourceCrop);
+    dumpVal(out, "bufferTransform%", toString(bufferTransform), bufferTransform);
+    dumpVal(out, "z-index", z);
+
+    if (hwc) {
+        dumpHwc(*hwc, out);
+    }
+
+    out.append("\n");
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index d546fc8..b4dfba1 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include <android-base/stringprintf.h>
 #include <android/native_window.h>
 #include <compositionengine/CompositionEngine.h>
@@ -28,6 +30,7 @@
 #include <system/window.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/Rect.h>
+#include <utils/Trace.h>
 
 #include "DisplayHardware/HWComposer.h"
 
@@ -99,11 +102,11 @@
     return mDisplaySurface->beginFrame(mustRecompose);
 }
 
-status_t RenderSurface::prepareFrame(std::vector<CompositionInfo>& compositionData) {
+status_t RenderSurface::prepareFrame() {
     auto& hwc = mCompositionEngine.getHwComposer();
     const auto id = mDisplay.getId();
     if (id) {
-        status_t error = hwc.prepare(*id, compositionData);
+        status_t error = hwc.prepare(*id, mDisplay);
         if (error != NO_ERROR) {
             return error;
         }
@@ -127,7 +130,8 @@
     return mDisplaySurface->prepareFrame(compositionType);
 }
 
-sp<GraphicBuffer> RenderSurface::dequeueBuffer() {
+sp<GraphicBuffer> RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) {
+    ATRACE_CALL();
     int fd = -1;
     ANativeWindowBuffer* buffer = nullptr;
 
@@ -145,18 +149,12 @@
              mGraphicBuffer->getNativeBuffer()->handle);
     mGraphicBuffer = GraphicBuffer::from(buffer);
 
-    // Block until the buffer is ready
-    // TODO(alecmouri): it's perhaps more appropriate to block renderengine so
-    // that the gl driver can block instead.
-    if (fd >= 0) {
-        sync_wait(fd, -1);
-        close(fd);
-    }
+    *bufferFence = base::unique_fd(fd);
 
     return mGraphicBuffer;
 }
 
-void RenderSurface::queueBuffer() {
+void RenderSurface::queueBuffer(base::unique_fd&& readyFence) {
     auto& hwc = mCompositionEngine.getHwComposer();
     const auto id = mDisplay.getId();
 
@@ -172,15 +170,16 @@
             // We shouldn't deadlock here, since mGraphicBuffer == nullptr only
             // after a successful call to queueBuffer, or if dequeueBuffer has
             // never been called.
-            dequeueBuffer();
+            base::unique_fd unused;
+            dequeueBuffer(&unused);
         }
 
         if (mGraphicBuffer == nullptr) {
             ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str());
         } else {
-            status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(),
-                                                         mGraphicBuffer->getNativeBuffer(),
-                                                         dup(mBufferReady));
+            status_t result =
+                    mNativeWindow->queueBuffer(mNativeWindow.get(),
+                                               mGraphicBuffer->getNativeBuffer(), dup(readyFence));
             if (result != NO_ERROR) {
                 ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(),
                       result);
@@ -190,12 +189,10 @@
                     LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result);
                 } else {
                     mNativeWindow->cancelBuffer(mNativeWindow.get(),
-                                                mGraphicBuffer->getNativeBuffer(),
-                                                dup(mBufferReady));
+                                                mGraphicBuffer->getNativeBuffer(), dup(readyFence));
                 }
             }
 
-            mBufferReady.reset();
             mGraphicBuffer = nullptr;
         }
     }
@@ -217,14 +214,6 @@
                                           ui::Transform::ROT_0);
 }
 
-void RenderSurface::finishBuffer() {
-    auto& renderEngine = mCompositionEngine.getRenderEngine();
-    mBufferReady = renderEngine.flush();
-    if (mBufferReady.get() < 0) {
-        renderEngine.finish();
-    }
-}
-
 void RenderSurface::flip() {
     mPageFlipCount++;
 }
@@ -263,9 +252,5 @@
     return mGraphicBuffer;
 }
 
-base::unique_fd& RenderSurface::mutableBufferReadyForTest() {
-    return mBufferReady;
-}
-
 } // namespace impl
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
index d20fdda..9215884 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
@@ -146,6 +146,8 @@
         return ProfileFactory()
                 .setHasWideColorGamut(true)
                 .addHdrType(Hdr::HDR10)
+                .addColorModeRenderIntent(ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC)
+                .addColorModeRenderIntent(ColorMode::DISPLAY_BT2020, RenderIntent::ENHANCE)
                 .addColorModeRenderIntent(ColorMode::DISPLAY_BT2020, VendorRenderIntent)
                 .build();
     }
@@ -154,6 +156,8 @@
         return ProfileFactory()
                 .setHasWideColorGamut(true)
                 .addHdrType(Hdr::HDR10)
+                .addColorModeRenderIntent(ColorMode::SRGB, RenderIntent::COLORIMETRIC)
+                .addColorModeRenderIntent(ColorMode::SRGB, RenderIntent::ENHANCE)
                 .addColorModeRenderIntent(ColorMode::SRGB, VendorRenderIntent)
                 .build();
     }
@@ -166,6 +170,16 @@
                 .build();
     }
 
+    static impl::DisplayColorProfile createProfileWithDisplayP3ColorModeSupport() {
+        return ProfileFactory()
+                .setHasWideColorGamut(true)
+                .addHdrType(Hdr::HLG)
+                .addColorModeRenderIntent(ColorMode::DISPLAY_P3, RenderIntent::COLORIMETRIC)
+                .addColorModeRenderIntent(ColorMode::DISPLAY_P3, RenderIntent::ENHANCE)
+                .addColorModeRenderIntent(ColorMode::DISPLAY_P3, VendorRenderIntent)
+                .build();
+    }
+
 private:
     bool mHasWideColorGamut = false;
     std::vector<Hdr> mSupportedHdrTypes;
@@ -348,7 +362,7 @@
     auto profile = ProfileFactory::createProfileWithBT2020ColorModeSupport();
 
     EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
-    EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+    EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::ENHANCE));
     EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
     EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
     EXPECT_FALSE(profile.hasRenderIntent(VendorRenderIntent));
@@ -358,7 +372,7 @@
     auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
 
     EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
-    EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+    EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::ENHANCE));
     EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
     EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
     EXPECT_TRUE(profile.hasRenderIntent(VendorRenderIntent));
@@ -414,47 +428,37 @@
 
 void checkGetBestColorMode(
         DisplayColorProfile& profile,
-        const std::array<std::tuple<Dataspace, ColorMode, RenderIntent>, 25>& expected) {
+        const std::array<std::tuple<Dataspace, ColorMode, RenderIntent>, 15>& expected) {
     using ArgsType = std::tuple<Dataspace, RenderIntent>;
 
     // These are the combinations of dataspaces and render intents that could be
     // passed to RenderSurface::getBestColorMode()
-    const std::array<std::tuple<Dataspace, RenderIntent>, 25> kArgs = {
+    const std::array<std::tuple<Dataspace, RenderIntent>, 15> kArgs = {
             /* clang-format off */
 
             // Non-HDR combinations
 
             /*  0 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
             /*  1 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::ENHANCE},
-            /*  2 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::TONE_MAP_COLORIMETRIC}, // Vendor explicit setting
-            /*  3 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::TONE_MAP_ENHANCE},      // Vendor explicit setting
-            /*  4 */ ArgsType{Dataspace::DISPLAY_BT2020, VendorRenderIntent},                  // Vendor explicit setting
+            /*  2 */ ArgsType{Dataspace::DISPLAY_BT2020, VendorRenderIntent},                  // Vendor explicit setting
 
-            /*  5 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::COLORIMETRIC},
-            /*  6 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::ENHANCE},
-            /*  7 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::TONE_MAP_COLORIMETRIC}, // Vendor explicit setting
-            /*  8 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::TONE_MAP_ENHANCE},      // Vendor explicit setting
-            /*  9 */ ArgsType{Dataspace::DISPLAY_P3, VendorRenderIntent},                  // Vendor explicit setting
+            /*  3 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::COLORIMETRIC},
+            /*  4 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::ENHANCE},
+            /*  5 */ ArgsType{Dataspace::DISPLAY_P3, VendorRenderIntent},                  // Vendor explicit setting
 
-            /* 10 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::COLORIMETRIC},
-            /* 11 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::ENHANCE},
-            /* 12 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::TONE_MAP_COLORIMETRIC}, // Vendor explicit setting
-            /* 13 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::TONE_MAP_ENHANCE},      // Vendor explicit setting
-            /* 14 */ ArgsType{Dataspace::V0_SRGB, VendorRenderIntent},                  // Vendor explicit setting
+            /*  6 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::COLORIMETRIC},
+            /*  7 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::ENHANCE},
+            /*  8 */ ArgsType{Dataspace::V0_SRGB, VendorRenderIntent},                  // Vendor explicit setting
 
             // HDR combinations
 
-            /* 15 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::TONE_MAP_COLORIMETRIC},
-            /* 16 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::TONE_MAP_ENHANCE},
-            /* 17 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::COLORIMETRIC},       // Vendor explicit setting
-            /* 18 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::ENHANCE},            // Vendor explicit setting
-            /* 19 */ ArgsType{Dataspace::BT2020_PQ, VendorRenderIntent},               // Vendor explicit setting
+            /*  9 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::TONE_MAP_COLORIMETRIC},
+            /* 10 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::TONE_MAP_ENHANCE},
+            /* 11 */ ArgsType{Dataspace::BT2020_PQ, VendorRenderIntent},               // Vendor explicit setting
 
-            /* 20 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::TONE_MAP_COLORIMETRIC},
-            /* 21 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::TONE_MAP_ENHANCE},
-            /* 22 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::COLORIMETRIC},       // Vendor explicit setting
-            /* 23 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::ENHANCE},            // Vendor explicit setting
-            /* 24 */ ArgsType{Dataspace::BT2020_HLG, VendorRenderIntent},               // Vendor explicit setting
+            /* 12 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::TONE_MAP_COLORIMETRIC},
+            /* 13 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::TONE_MAP_ENHANCE},
+            /* 14 */ ArgsType{Dataspace::BT2020_HLG, VendorRenderIntent},               // Vendor explicit setting
             /* clang-format on */
     };
 
@@ -473,38 +477,28 @@
     // Note: This table of expected values goes with the table of arguments
     // used in checkGetBestColorMode.
     using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
-    std::array<Result, 25> expectedResults = {
+    std::array<Result, 15> expectedResults = {
             /* clang-format off */
             /*  0 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /*  1 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /*  2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
             /*  3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /*  4 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-
             /*  5 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
             /*  6 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /*  7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /*  8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /*  9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
 
+            /*  9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /* 10 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /* 11 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
             /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
 
-            /* 15 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 16 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-
-            /* 20 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 21 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-
             /* clang-format on */
     };
 
@@ -517,37 +511,27 @@
     // Note: This table of expected values goes with the table of arguments
     // used in checkGetBestColorMode.
     using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
-    std::array<Result, 25> expectedResults = {
+    std::array<Result, 15> expectedResults = {
             /* clang-format off */
             /*  0 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
-            /*  1 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+            /*  1 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::ENHANCE},
             /*  2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /*  3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /*  4 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
 
-            /*  5 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+            /*  3 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+            /*  4 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::ENHANCE},
+            /*  5 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
             /*  6 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
-            /*  7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+            /*  7 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::ENHANCE},
             /*  8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /*  9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
 
+            /*  9 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
             /* 10 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
-            /* 11 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
-            /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+            /* 11 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+            /* 12 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+            /* 13 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
             /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-
-            /* 15 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
-            /* 16 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
-            /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-
-            /* 20 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
-            /* 21 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
-            /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /* clang-format on */
     };
 
@@ -560,37 +544,61 @@
     // Note: This table of expected values goes with the table of arguments
     // used in checkGetBestColorMode.
     using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
-    std::array<Result, 25> expectedResults = {
+    std::array<Result, 15> expectedResults = {
             /* clang-format off */
             /*  0 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
-            /*  1 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
-            /*  2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /*  3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /*  4 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+            /*  1 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::ENHANCE},
+            /*  2 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
 
-            /*  5 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+            /*  3 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+            /*  4 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::ENHANCE},
+            /*  5 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+
             /*  6 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
-            /*  7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /*  8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /*  9 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+            /*  7 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::ENHANCE},
+            /*  8 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
 
+            /*  9 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
             /* 10 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
-            /* 11 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
-            /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 14 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+            /* 11 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
 
-            /* 15 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
-            /* 16 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
-            /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+            /* 12 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+            /* 13 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+            /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+            /* clang-format on */
+    };
 
-            /* 20 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
-            /* 21 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
-            /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+    checkGetBestColorMode(profile, expectedResults);
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasDisplayP3Support) {
+    auto profile = ProfileFactory::createProfileWithDisplayP3ColorModeSupport();
+
+    // Note: This table of expected values goes with the table of arguments
+    // used in checkGetBestColorMode.
+    using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+    std::array<Result, 15> expectedResults = {
+            /* clang-format off */
+            /*  0 */ Result{Dataspace::DISPLAY_P3, ColorMode::DISPLAY_P3, RenderIntent::COLORIMETRIC},
+            /*  1 */ Result{Dataspace::DISPLAY_P3, ColorMode::DISPLAY_P3, RenderIntent::ENHANCE},
+            // TODO(b/124317977): There is bug here.
+            /*  2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+            /*  3 */ Result{Dataspace::DISPLAY_P3, ColorMode::DISPLAY_P3, RenderIntent::COLORIMETRIC},
+            /*  4 */ Result{Dataspace::DISPLAY_P3, ColorMode::DISPLAY_P3, RenderIntent::ENHANCE},
+            /*  5 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+            /*  6 */ Result{Dataspace::DISPLAY_P3, ColorMode::DISPLAY_P3, RenderIntent::COLORIMETRIC},
+            /*  7 */ Result{Dataspace::DISPLAY_P3, ColorMode::DISPLAY_P3, RenderIntent::ENHANCE},
+            /*  8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+            /*  9 */ Result{Dataspace::DISPLAY_P3, ColorMode::DISPLAY_P3, RenderIntent::COLORIMETRIC},
+            /* 10 */ Result{Dataspace::DISPLAY_P3, ColorMode::DISPLAY_P3, RenderIntent::COLORIMETRIC},
+            /* 11 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+            /* 12 */ Result{Dataspace::DISPLAY_P3, ColorMode::DISPLAY_P3, RenderIntent::COLORIMETRIC},
+            /* 13 */ Result{Dataspace::DISPLAY_P3, ColorMode::DISPLAY_P3, RenderIntent::COLORIMETRIC},
+            /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /* clang-format on */
     };
 
@@ -603,37 +611,27 @@
     // Note: This table of expected values goes with the table of arguments
     // used in checkGetBestColorMode.
     using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
-    std::array<Result, 25> expectedResults = {
+    std::array<Result, 15> expectedResults = {
             /* clang-format off */
             /*  0 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /*  1 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /*  2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
             /*  3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /*  4 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-
             /*  5 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
             /*  6 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /*  7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
             /*  8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /*  9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
 
-            /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 11 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+            /*  9 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+            /* 10 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+            /* 11 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, VendorRenderIntent},
 
-            /* 15 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
-            /* 16 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
-            /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-
-            /* 20 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
-            /* 21 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
-            /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
-            /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+            /* 12 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+            /* 13 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+            /* 14 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, VendorRenderIntent},
             /* clang-format on */
     };
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 8cb6936..cd2d454 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -156,17 +156,17 @@
     EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
 
     // Otherwise if the values are different, updates happen
-    EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+    EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
     EXPECT_CALL(mHwComposer,
-                setActiveColorMode(DEFAULT_DISPLAY_ID, ui::ColorMode::BT2100_PQ,
+                setActiveColorMode(DEFAULT_DISPLAY_ID, ui::ColorMode::DISPLAY_P3,
                                    ui::RenderIntent::TONE_MAP_COLORIMETRIC))
             .Times(1);
 
-    mDisplay.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+    mDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
                           ui::RenderIntent::TONE_MAP_COLORIMETRIC);
 
-    EXPECT_EQ(ui::ColorMode::BT2100_PQ, mDisplay.getState().colorMode);
-    EXPECT_EQ(ui::Dataspace::SRGB, mDisplay.getState().dataspace);
+    EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay.getState().colorMode);
+    EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay.getState().dataspace);
     EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay.getState().renderIntent);
 }
 
@@ -174,7 +174,7 @@
     impl::Display virtualDisplay{mCompositionEngine,
                                  DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}};
 
-    virtualDisplay.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+    virtualDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
                                 ui::RenderIntent::TONE_MAP_COLORIMETRIC);
 
     EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode);
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.cpp b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.cpp
new file mode 100644
index 0000000..8c10341
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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 "MockHWC2.h"
+
+namespace HWC2 {
+
+// This will go away once HWC2::Layer is moved into the "backend" library
+Layer::~Layer() = default;
+
+namespace mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+Layer::Layer() = default;
+Layer::~Layer() = default;
+
+} // namespace mock
+} // namespace HWC2
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
new file mode 100644
index 0000000..7fd6541
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -0,0 +1,63 @@
+/*
+ * 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 <ui/Fence.h>
+#include <ui/FloatRect.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+#include "DisplayHardware/HWC2.h"
+
+namespace HWC2 {
+namespace mock {
+
+class Layer : public HWC2::Layer {
+public:
+    Layer();
+    ~Layer() override;
+
+    MOCK_CONST_METHOD0(getId, hwc2_layer_t());
+
+    MOCK_METHOD2(setCursorPosition, Error(int32_t, int32_t));
+    MOCK_METHOD3(setBuffer,
+                 Error(uint32_t, const android::sp<android::GraphicBuffer>&,
+                       const android::sp<android::Fence>&));
+    MOCK_METHOD1(setSurfaceDamage, Error(const android::Region&));
+    MOCK_METHOD1(setBlendMode, Error(BlendMode));
+    MOCK_METHOD1(setColor, Error(hwc_color_t));
+    MOCK_METHOD1(setCompositionType, Error(Composition));
+    MOCK_METHOD1(setDataspace, Error(android::ui::Dataspace));
+    MOCK_METHOD2(setPerFrameMetadata, Error(const int32_t, const android::HdrMetadata&));
+    MOCK_METHOD1(setDisplayFrame, Error(const android::Rect&));
+    MOCK_METHOD1(setPlaneAlpha, Error(float));
+    MOCK_METHOD1(setSidebandStream, Error(const native_handle_t*));
+    MOCK_METHOD1(setSourceCrop, Error(const android::FloatRect&));
+    MOCK_METHOD1(setTransform, Error(Transform));
+    MOCK_METHOD1(setVisibleRegion, Error(const android::Region&));
+    MOCK_METHOD1(setZOrder, Error(uint32_t));
+    MOCK_METHOD2(setInfo, Error(uint32_t, uint32_t));
+
+    MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
+};
+
+} // namespace mock
+} // namespace HWC2
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index ece412f..885cdd4 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -16,10 +16,9 @@
 
 #pragma once
 
+#include <compositionengine/Output.h>
 #include <gmock/gmock.h>
 
-#include "LayerBE.h"
-
 #include "DisplayHardware/HWComposer.h"
 
 namespace android {
@@ -41,7 +40,7 @@
                  std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
     MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId));
     MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*));
-    MOCK_METHOD2(prepare, status_t(DisplayId, std::vector<CompositionInfo>&));
+    MOCK_METHOD2(prepare, status_t(DisplayId, const compositionengine::Output&));
     MOCK_METHOD5(setClientTarget,
                  status_t(DisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&,
                           ui::Dataspace));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 0a929ac..f7dcf6f 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -15,16 +15,22 @@
  */
 
 #include <compositionengine/impl/OutputLayer.h>
+#include <compositionengine/mock/CompositionEngine.h>
 #include <compositionengine/mock/Layer.h>
 #include <compositionengine/mock/LayerFE.h>
 #include <compositionengine/mock/Output.h>
 #include <gtest/gtest.h>
 
+#include "MockHWC2.h"
+#include "MockHWComposer.h"
+
 namespace android::compositionengine {
 namespace {
 
 using testing::StrictMock;
 
+constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
+
 class OutputLayerTest : public testing::Test {
 public:
     ~OutputLayerTest() override = default;
@@ -43,5 +49,37 @@
 
 TEST_F(OutputLayerTest, canInstantiateOutputLayer) {}
 
+/* ------------------------------------------------------------------------
+ * OutputLayer::initialize()
+ */
+
+TEST_F(OutputLayerTest, initializingOutputLayerWithoutHwcDoesNothingInteresting) {
+    StrictMock<compositionengine::mock::CompositionEngine> compositionEngine;
+
+    mOutputLayer.initialize(compositionEngine, std::nullopt);
+
+    EXPECT_FALSE(mOutputLayer.getState().hwc);
+}
+
+TEST_F(OutputLayerTest, initializingOutputLayerWithHwcDisplayCreatesHwcLayer) {
+    StrictMock<compositionengine::mock::CompositionEngine> compositionEngine;
+    StrictMock<android::mock::HWComposer> hwc;
+    StrictMock<HWC2::mock::Layer> hwcLayer;
+
+    EXPECT_CALL(compositionEngine, getHwComposer()).WillOnce(ReturnRef(hwc));
+    EXPECT_CALL(hwc, createLayer(DEFAULT_DISPLAY_ID)).WillOnce(Return(&hwcLayer));
+
+    mOutputLayer.initialize(compositionEngine, DEFAULT_DISPLAY_ID);
+
+    const auto& state = mOutputLayer.getState();
+    ASSERT_TRUE(state.hwc);
+
+    const auto& hwcState = *state.hwc;
+    EXPECT_EQ(&hwcLayer, hwcState.hwcLayer.get());
+
+    EXPECT_CALL(hwc, destroyLayer(DEFAULT_DISPLAY_ID, &hwcLayer));
+    mOutputLayer.editState().hwc.reset();
+}
+
 } // namespace
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index cc1211b..a84af3a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -43,15 +43,21 @@
         mOutput.setDisplayColorProfileForTest(
                 std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
         mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+
+        mOutput.editState().bounds = kDefaultDisplaySize;
     }
     ~OutputTest() override = default;
 
+    static const Rect kDefaultDisplaySize;
+
     StrictMock<mock::CompositionEngine> mCompositionEngine;
     mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
     mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
     impl::Output mOutput{mCompositionEngine};
 };
 
+const Rect OutputTest::kDefaultDisplaySize{100, 200};
+
 /* ------------------------------------------------------------------------
  * Basic construction
  */
@@ -76,8 +82,6 @@
  */
 
 TEST_F(OutputTest, setCompositionEnabledDoesNothingIfAlreadyEnabled) {
-    const Rect displaySize{100, 200};
-    mOutput.editState().bounds = displaySize;
     mOutput.editState().isEnabled = true;
 
     mOutput.setCompositionEnabled(true);
@@ -87,25 +91,21 @@
 }
 
 TEST_F(OutputTest, setCompositionEnabledSetsEnabledAndDirtiesEntireOutput) {
-    const Rect displaySize{100, 200};
-    mOutput.editState().bounds = displaySize;
     mOutput.editState().isEnabled = false;
 
     mOutput.setCompositionEnabled(true);
 
     EXPECT_TRUE(mOutput.getState().isEnabled);
-    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
 }
 
 TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) {
-    const Rect displaySize{100, 200};
-    mOutput.editState().bounds = displaySize;
     mOutput.editState().isEnabled = true;
 
     mOutput.setCompositionEnabled(false);
 
     EXPECT_FALSE(mOutput.getState().isEnabled);
-    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
 }
 
 /* ------------------------------------------------------------------------
@@ -135,7 +135,7 @@
  */
 
 TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
-    const ui::Size displaySize{100, 200};
+    const ui::Size displaySize{200, 400};
 
     EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
     EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
@@ -152,16 +152,13 @@
  */
 
 TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) {
-    const Rect displaySize{100, 200};
-    mOutput.editState().bounds = displaySize;
-
     const uint32_t layerStack = 123u;
     mOutput.setLayerStackFilter(layerStack, true);
 
     EXPECT_TRUE(mOutput.getState().layerStackInternal);
     EXPECT_EQ(layerStack, mOutput.getState().layerStackId);
 
-    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
 }
 
 /* ------------------------------------------------------------------------
@@ -176,27 +173,45 @@
 
     EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform);
 
+    // Since identity is the default, the dirty region should be unchanged (empty)
+    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
+
     // Non-identity matrix sets a non-identity state value
     const mat4 nonIdentity = mat4() * 2;
 
     mOutput.setColorTransform(nonIdentity);
 
     EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
+
+    // Since this is a state change, the entire output should now be dirty.
+    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
 }
 
 /* ------------------------------------------------------------------------
  * Output::setColorMode
  */
 
-TEST_F(OutputTest, setColorModeSetsModeUnlessNoChange) {
-    EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) {
+    EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
 
-    mOutput.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+    mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
                          ui::RenderIntent::TONE_MAP_COLORIMETRIC);
 
-    EXPECT_EQ(ui::ColorMode::BT2100_PQ, mOutput.getState().colorMode);
-    EXPECT_EQ(ui::Dataspace::SRGB, mOutput.getState().dataspace);
+    EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput.getState().colorMode);
+    EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput.getState().dataspace);
     EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent);
+    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+}
+
+TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) {
+    mOutput.editState().colorMode = ui::ColorMode::DISPLAY_P3;
+    mOutput.editState().dataspace = ui::Dataspace::DISPLAY_P3;
+    mOutput.editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC;
+
+    mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+                         ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+
+    EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
 }
 
 /* ------------------------------------------------------------------------
@@ -215,52 +230,32 @@
 }
 
 /* ------------------------------------------------------------------------
- * Output::getPhysicalSpaceDirtyRegion()
+ * Output::getDirtyRegion()
  */
 
-TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingTrue) {
-    const Rect displaySize{100, 200};
-    mOutput.editState().bounds = displaySize;
+TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingTrue) {
+    const Rect viewport{100, 200};
+    mOutput.editState().viewport = viewport;
     mOutput.editState().dirtyRegion.set(50, 300);
 
     {
-        Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
+        Region result = mOutput.getDirtyRegion(true);
 
-        EXPECT_THAT(result, RegionEq(Region(displaySize)));
-    }
-
-    // For repaint everything == true, the returned value does not depend on the display
-    // rotation.
-    mOutput.editState().transform.set(ui::Transform::ROT_90, 0, 0);
-
-    {
-        Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
-
-        EXPECT_THAT(result, RegionEq(Region(displaySize)));
+        EXPECT_THAT(result, RegionEq(Region(viewport)));
     }
 }
 
-TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingFalse) {
-    const Rect displaySize{100, 200};
-    mOutput.editState().bounds = displaySize;
+TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) {
+    const Rect viewport{100, 200};
+    mOutput.editState().viewport = viewport;
     mOutput.editState().dirtyRegion.set(50, 300);
 
     {
-        Region result = mOutput.getPhysicalSpaceDirtyRegion(false);
+        Region result = mOutput.getDirtyRegion(false);
 
         // The dirtyRegion should be clipped to the display bounds.
         EXPECT_THAT(result, RegionEq(Region(Rect(50, 200))));
     }
-
-    mOutput.editState().transform.set(ui::Transform::ROT_90, displaySize.getWidth(),
-                                      displaySize.getHeight());
-
-    {
-        Region result = mOutput.getPhysicalSpaceDirtyRegion(false);
-
-        // The dirtyRegion should be rotated and clipped to the display bounds.
-        EXPECT_THAT(result, RegionEq(Region(Rect(100, 50))));
-    }
 }
 
 /* ------------------------------------------------------------------------
@@ -343,7 +338,7 @@
         // If there is no OutputLayer corresponding to the input layer, a
         // new OutputLayer is constructed and returned.
         EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(otherLayer));
-        auto result = mOutput.getOrCreateOutputLayer(layer, layerFE);
+        auto result = mOutput.getOrCreateOutputLayer(std::nullopt, layer, layerFE);
         EXPECT_NE(existingOutputLayer, result.get());
         EXPECT_TRUE(result.get() != nullptr);
         EXPECT_EQ(layer.get(), &result->getLayer());
@@ -359,7 +354,7 @@
         // If there is an existing OutputLayer for the requested layer, an owned
         // pointer is returned
         EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(*layer));
-        auto result = mOutput.getOrCreateOutputLayer(layer, layerFE);
+        auto result = mOutput.getOrCreateOutputLayer(std::nullopt, layer, layerFE);
         EXPECT_EQ(existingOutputLayer, result.get());
 
         // The corresponding entry in the ordered array should be cleared.
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 13cc663..84af9b9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -22,6 +22,7 @@
 #include <compositionengine/mock/CompositionEngine.h>
 #include <compositionengine/mock/Display.h>
 #include <compositionengine/mock/DisplaySurface.h>
+#include <compositionengine/mock/OutputLayer.h>
 #include <gtest/gtest.h>
 #include <renderengine/mock/RenderEngine.h>
 #include <system/window.h>
@@ -284,64 +285,66 @@
  * RenderSurface::prepareFrame()
  */
 
-TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
-    std::vector<CompositionInfo> data;
-
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data)))
+TEST_F(RenderSurfaceTest, prepareFramePassesOutputLayersToHwc) {
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
             .WillOnce(Return(INVALID_OPERATION));
 
-    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+            .WillOnce(Return(INVALID_OPERATION));
+
+    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) {
-    std::vector<CompositionInfo> data;
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+            .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
     EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
 
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED))
             .WillOnce(Return(INVALID_OPERATION));
 
-    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) {
-    std::vector<CompositionInfo> data;
-
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+            .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
     EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
 
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
             .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) {
-    std::vector<CompositionInfo> data;
-
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+            .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
     EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
 
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
             .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) {
-    std::vector<CompositionInfo> data;
-
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+            .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
     EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
 
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
             .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
 }
 
 /* ------------------------------------------------------------------------
@@ -355,7 +358,8 @@
             .WillOnce(
                     DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
 
-    EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer().get());
+    base::unique_fd fence;
+    EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence).get());
 
     EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
 }
@@ -373,7 +377,7 @@
             .WillOnce(Return(false));
     EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
 
-    mSurface.queueBuffer();
+    mSurface.queueBuffer(base::unique_fd());
 
     EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
 }
@@ -387,7 +391,7 @@
             .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
 
-    mSurface.queueBuffer();
+    mSurface.queueBuffer(base::unique_fd());
 
     EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
 }
@@ -402,7 +406,7 @@
             .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
 
-    mSurface.queueBuffer();
+    mSurface.queueBuffer(base::unique_fd());
 
     EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
 }
@@ -419,7 +423,7 @@
             .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
 
-    mSurface.queueBuffer();
+    mSurface.queueBuffer(base::unique_fd());
 
     EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
 }
@@ -436,7 +440,7 @@
             .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
 
-    mSurface.queueBuffer();
+    mSurface.queueBuffer(base::unique_fd());
 
     EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
 }
@@ -452,29 +456,6 @@
 }
 
 /* ------------------------------------------------------------------------
- * RenderSurface::finishBuffer()
- */
-
-TEST_F(RenderSurfaceTest, finishBufferJustFlushesRenderEngine) {
-    int fd = dup(1);
-
-    EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(fd))));
-
-    mSurface.finishBuffer();
-
-    EXPECT_EQ(fd, mSurface.mutableBufferReadyForTest().release());
-}
-
-TEST_F(RenderSurfaceTest, finishBufferFlushesAndFinishesRenderEngine) {
-    EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(-2))));
-    EXPECT_CALL(mRenderEngine, finish()).Times(1);
-
-    mSurface.finishBuffer();
-
-    EXPECT_EQ(-2, mSurface.mutableBufferReadyForTest().release());
-}
-
-/* ------------------------------------------------------------------------
  * RenderSurface::setViewportAndProjection()
  */
 
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index ca49f6c..22c40d7 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -26,12 +26,20 @@
 
 ContainerLayer::~ContainerLayer() = default;
 
-void ContainerLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) {}
+bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&,
+                                        renderengine::LayerSettings&) {
+    return false;
+}
 
 bool ContainerLayer::isVisible() const {
+    return false;
+}
+
+bool ContainerLayer::canReceiveInput() const {
     return !isHiddenByPolicy();
 }
 
-void ContainerLayer::setPerFrameData(DisplayId, const ui::Transform&, const Rect&, int32_t) {}
+void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
+                                     const Rect&, int32_t) {}
 
 } // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 413844b..c69997d 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -29,16 +29,21 @@
     ~ContainerLayer() override;
 
     const char* getTypeId() const override { return "ContainerLayer"; }
-    void onDraw(const RenderArea& renderArea, const Region& clip,
-                bool useIdentityTransform) override;
     bool isVisible() const override;
 
-    void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
-                         int32_t supportedPerFrameMetadata) override;
+    bool canReceiveInput() const override;
+
+    void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
+                         const Rect& viewport, int32_t supportedPerFrameMetadata) override;
 
     bool isCreatedFromMainThread() const override { return true; }
 
     bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
+
+protected:
+    bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+                            bool useIdentityTransform, Region& clearRegion,
+                            renderengine::LayerSettings& layer);
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 9674f0d..a827c47 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -266,6 +266,7 @@
     int getHeight() const override { return mDevice->getHeight(); }
     int getWidth() const override { return mDevice->getWidth(); }
     bool isSecure() const override { return mDevice->isSecure(); }
+    const sp<const DisplayDevice> getDisplayDevice() const override { return mDevice; }
 
     bool needsFiltering() const override {
         // check if the projection from the logical display to the physical
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index 1599995..d63cd79 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -23,10 +23,12 @@
 #include <string_view>
 #include <vector>
 
+#include <ui/GraphicTypes.h>
+
 namespace android {
 
 struct DisplayId {
-    using Type = uint64_t;
+    using Type = PhysicalDisplayId;
     Type value;
 
     uint16_t manufacturerId() const;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 68e7876..bca0abc 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -308,8 +308,7 @@
     return static_cast<Error>(intError);
 }
 
-Error Display::createLayer(Layer** outLayer)
-{
+Error Display::createLayer(HWC2::Layer** outLayer) {
     if (!outLayer) {
         return Error::BadParameter;
     }
@@ -320,15 +319,13 @@
         return error;
     }
 
-    auto layer = std::make_unique<Layer>(
-            mComposer, mCapabilities, mId, layerId);
+    auto layer = std::make_unique<impl::Layer>(mComposer, mCapabilities, mId, layerId);
     *outLayer = layer.get();
     mLayers.emplace(layerId, std::move(layer));
     return Error::None;
 }
 
-Error Display::destroyLayer(Layer* layer)
-{
+Error Display::destroyLayer(HWC2::Layer* layer) {
     if (!layer) {
         return Error::BadParameter;
     }
@@ -388,9 +385,7 @@
     return Error::None;
 }
 
-Error Display::getChangedCompositionTypes(
-        std::unordered_map<Layer*, Composition>* outTypes)
-{
+Error Display::getChangedCompositionTypes(std::unordered_map<HWC2::Layer*, Composition>* outTypes) {
     std::vector<Hwc2::Layer> layerIds;
     std::vector<Hwc2::IComposerClient::Composition> types;
     auto intError = mComposer.getChangedCompositionTypes(
@@ -492,8 +487,7 @@
 }
 
 Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests,
-        std::unordered_map<Layer*, LayerRequest>* outLayerRequests)
-{
+                           std::unordered_map<HWC2::Layer*, LayerRequest>* outLayerRequests) {
     uint32_t intDisplayRequests;
     std::vector<Hwc2::Layer> layerIds;
     std::vector<uint32_t> layerRequests;
@@ -574,9 +568,7 @@
     return static_cast<Error>(intError);
 }
 
-Error Display::getReleaseFences(
-        std::unordered_map<Layer*, sp<Fence>>* outFences) const
-{
+Error Display::getReleaseFences(std::unordered_map<HWC2::Layer*, sp<Fence>>* outFences) const {
     std::vector<Hwc2::Layer> layerIds;
     std::vector<int> fenceFds;
     auto intError = mComposer.getReleaseFences(mId, &layerIds, &fenceFds);
@@ -586,7 +578,7 @@
         return error;
     }
 
-    std::unordered_map<Layer*, sp<Fence>> releaseFences;
+    std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
     releaseFences.reserve(numElements);
     for (uint32_t element = 0; element < numElements; ++element) {
         auto layer = getLayerById(layerIds[element]);
@@ -787,8 +779,7 @@
 
 // Other Display methods
 
-Layer* Display::getLayerById(hwc2_layer_t id) const
-{
+HWC2::Layer* Display::getLayerById(hwc2_layer_t id) const {
     if (mLayers.count(id) == 0) {
         return nullptr;
     }
@@ -799,6 +790,10 @@
 
 // Layer methods
 
+Layer::~Layer() = default;
+
+namespace impl {
+
 Layer::Layer(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
              hwc2_display_t displayId, hwc2_layer_t layerId)
   : mComposer(composer),
@@ -817,15 +812,6 @@
     ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")"
             " failed: %s (%d)", mDisplayId, mId, to_string(error).c_str(),
             intError);
-    if (mLayerDestroyedListener) {
-        mLayerDestroyedListener(this);
-    }
-}
-
-void Layer::setLayerDestroyedListener(std::function<void(Layer*)> listener) {
-    LOG_ALWAYS_FATAL_IF(mLayerDestroyedListener && listener,
-            "Attempt to set layer destroyed listener multiple times");
-    mLayerDestroyedListener = listener;
 }
 
 Error Layer::setCursorPosition(int32_t x, int32_t y)
@@ -1033,4 +1019,6 @@
     auto intError = mComposer.setLayerColorTransform(mDisplayId, mId, matrix.asArray());
     return static_cast<Error>(intError);
 }
+
+} // namespace impl
 } // namespace HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index c1f481a..70358a0 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -364,52 +364,73 @@
 };
 } // namespace impl
 
+class Layer {
+public:
+    virtual ~Layer();
+
+    virtual hwc2_layer_t getId() const = 0;
+
+    [[clang::warn_unused_result]] virtual Error setCursorPosition(int32_t x, int32_t y) = 0;
+    [[clang::warn_unused_result]] virtual Error setBuffer(
+            uint32_t slot, const android::sp<android::GraphicBuffer>& buffer,
+            const android::sp<android::Fence>& acquireFence) = 0;
+    [[clang::warn_unused_result]] virtual Error setSurfaceDamage(const android::Region& damage) = 0;
+
+    [[clang::warn_unused_result]] virtual Error setBlendMode(BlendMode mode) = 0;
+    [[clang::warn_unused_result]] virtual Error setColor(hwc_color_t color) = 0;
+    [[clang::warn_unused_result]] virtual Error setCompositionType(Composition type) = 0;
+    [[clang::warn_unused_result]] virtual Error setDataspace(android::ui::Dataspace dataspace) = 0;
+    [[clang::warn_unused_result]] virtual Error setPerFrameMetadata(
+            const int32_t supportedPerFrameMetadata, const android::HdrMetadata& metadata) = 0;
+    [[clang::warn_unused_result]] virtual Error setDisplayFrame(const android::Rect& frame) = 0;
+    [[clang::warn_unused_result]] virtual Error setPlaneAlpha(float alpha) = 0;
+    [[clang::warn_unused_result]] virtual Error setSidebandStream(
+            const native_handle_t* stream) = 0;
+    [[clang::warn_unused_result]] virtual Error setSourceCrop(const android::FloatRect& crop) = 0;
+    [[clang::warn_unused_result]] virtual Error setTransform(Transform transform) = 0;
+    [[clang::warn_unused_result]] virtual Error setVisibleRegion(const android::Region& region) = 0;
+    [[clang::warn_unused_result]] virtual Error setZOrder(uint32_t z) = 0;
+    [[clang::warn_unused_result]] virtual Error setInfo(uint32_t type, uint32_t appId) = 0;
+
+    // Composer HAL 2.3
+    [[clang::warn_unused_result]] virtual Error setColorTransform(const android::mat4& matrix) = 0;
+};
+
+namespace impl {
+
 // Convenience C++ class to access hwc2_device_t Layer functions directly.
-class Layer
-{
+
+class Layer : public HWC2::Layer {
 public:
     Layer(android::Hwc2::Composer& composer,
           const std::unordered_set<Capability>& capabilities,
           hwc2_display_t displayId, hwc2_layer_t layerId);
-    ~Layer();
+    ~Layer() override;
 
-    hwc2_layer_t getId() const { return mId; }
+    hwc2_layer_t getId() const override { return mId; }
 
-    // Register a listener to be notified when the layer is destroyed. When the
-    // listener function is called, the Layer will be in the process of being
-    // destroyed, so it's not safe to call methods on it.
-    void setLayerDestroyedListener(std::function<void(Layer*)> listener);
+    Error setCursorPosition(int32_t x, int32_t y) override;
+    Error setBuffer(uint32_t slot, const android::sp<android::GraphicBuffer>& buffer,
+                    const android::sp<android::Fence>& acquireFence) override;
+    Error setSurfaceDamage(const android::Region& damage) override;
 
-    [[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y);
-    [[clang::warn_unused_result]] Error setBuffer(uint32_t slot,
-            const android::sp<android::GraphicBuffer>& buffer,
-            const android::sp<android::Fence>& acquireFence);
-    [[clang::warn_unused_result]] Error setSurfaceDamage(
-            const android::Region& damage);
-
-    [[clang::warn_unused_result]] Error setBlendMode(BlendMode mode);
-    [[clang::warn_unused_result]] Error setColor(hwc_color_t color);
-    [[clang::warn_unused_result]] Error setCompositionType(Composition type);
-    [[clang::warn_unused_result]] Error setDataspace(
-            android::ui::Dataspace dataspace);
-    [[clang::warn_unused_result]] Error setPerFrameMetadata(
-            const int32_t supportedPerFrameMetadata,
-            const android::HdrMetadata& metadata);
-    [[clang::warn_unused_result]] Error setDisplayFrame(
-            const android::Rect& frame);
-    [[clang::warn_unused_result]] Error setPlaneAlpha(float alpha);
-    [[clang::warn_unused_result]] Error setSidebandStream(
-            const native_handle_t* stream);
-    [[clang::warn_unused_result]] Error setSourceCrop(
-            const android::FloatRect& crop);
-    [[clang::warn_unused_result]] Error setTransform(Transform transform);
-    [[clang::warn_unused_result]] Error setVisibleRegion(
-            const android::Region& region);
-    [[clang::warn_unused_result]] Error setZOrder(uint32_t z);
-    [[clang::warn_unused_result]] Error setInfo(uint32_t type, uint32_t appId);
+    Error setBlendMode(BlendMode mode) override;
+    Error setColor(hwc_color_t color) override;
+    Error setCompositionType(Composition type) override;
+    Error setDataspace(android::ui::Dataspace dataspace) override;
+    Error setPerFrameMetadata(const int32_t supportedPerFrameMetadata,
+                              const android::HdrMetadata& metadata) override;
+    Error setDisplayFrame(const android::Rect& frame) override;
+    Error setPlaneAlpha(float alpha) override;
+    Error setSidebandStream(const native_handle_t* stream) override;
+    Error setSourceCrop(const android::FloatRect& crop) override;
+    Error setTransform(Transform transform) override;
+    Error setVisibleRegion(const android::Region& region) override;
+    Error setZOrder(uint32_t z) override;
+    Error setInfo(uint32_t type, uint32_t appId) override;
 
     // Composer HAL 2.3
-    [[clang::warn_unused_result]] Error setColorTransform(const android::mat4& matrix);
+    Error setColorTransform(const android::mat4& matrix) override;
 
 private:
     // These are references to data owned by HWC2::Device, which will outlive
@@ -422,10 +443,11 @@
     hwc2_layer_t mId;
     android::ui::Dataspace mDataSpace = android::ui::Dataspace::UNKNOWN;
     android::HdrMetadata mHdrMetadata;
-    std::function<void(Layer*)> mLayerDestroyedListener;
     android::mat4 mColorMatrix;
 };
 
+} // namespace impl
+
 } // namespace HWC2
 
 #endif // ANDROID_SF_HWC2_H
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 5b4d347..3b9e0e6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -20,13 +20,14 @@
 #define LOG_TAG "HWComposer"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <utils/Errors.h>
-#include <utils/Trace.h>
-
+#include <compositionengine/Output.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <log/log.h>
 #include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
-
-#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/Trace.h>
 
 #include "HWComposer.h"
 #include "HWC2.h"
@@ -398,7 +399,7 @@
     return NO_ERROR;
 }
 
-status_t HWComposer::prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData) {
+status_t HWComposer::prepare(DisplayId displayId, const compositionengine::Output& output) {
     ATRACE_CALL();
 
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
@@ -462,47 +463,42 @@
 
     displayData.hasClientComposition = false;
     displayData.hasDeviceComposition = false;
-    for (auto& compositionInfo : compositionData) {
-        auto hwcLayer = compositionInfo.hwc.hwcLayer;
+    for (auto& outputLayer : output.getOutputLayersOrderedByZ()) {
+        auto& state = outputLayer->editState();
+        LOG_FATAL_IF(!state.hwc.);
+        auto hwcLayer = (*state.hwc).hwcLayer;
 
-        if (changedTypes.count(&*hwcLayer) != 0) {
-            // We pass false so we only update our state and don't call back
-            // into the HWC device
-            validateChange(compositionInfo.compositionType,
-                    changedTypes[&*hwcLayer]);
-            compositionInfo.compositionType = changedTypes[&*hwcLayer];
-            compositionInfo.layer->mLayer->setCompositionType(displayId,
-                                                              compositionInfo.compositionType,
-                                                              false);
+        if (auto it = changedTypes.find(hwcLayer.get()); it != changedTypes.end()) {
+            auto newCompositionType = it->second;
+            validateChange(static_cast<HWC2::Composition>((*state.hwc).hwcCompositionType),
+                           newCompositionType);
+            (*state.hwc).hwcCompositionType =
+                    static_cast<Hwc2::IComposerClient::Composition>(newCompositionType);
         }
 
-        switch (compositionInfo.compositionType) {
-            case HWC2::Composition::Client:
+        switch ((*state.hwc).hwcCompositionType) {
+            case Hwc2::IComposerClient::Composition::CLIENT:
                 displayData.hasClientComposition = true;
                 break;
-            case HWC2::Composition::Device:
-            case HWC2::Composition::SolidColor:
-            case HWC2::Composition::Cursor:
-            case HWC2::Composition::Sideband:
+            case Hwc2::IComposerClient::Composition::DEVICE:
+            case Hwc2::IComposerClient::Composition::SOLID_COLOR:
+            case Hwc2::IComposerClient::Composition::CURSOR:
+            case Hwc2::IComposerClient::Composition::SIDEBAND:
                 displayData.hasDeviceComposition = true;
                 break;
             default:
                 break;
         }
 
-        if (layerRequests.count(&*hwcLayer) != 0 &&
-                layerRequests[&*hwcLayer] ==
-                        HWC2::LayerRequest::ClearClientTarget) {
-            compositionInfo.hwc.clearClientTarget = true;
-            compositionInfo.layer->mLayer->setClearClientTarget(displayId, true);
-        } else {
-            if (layerRequests.count(&*hwcLayer) != 0) {
+        state.clearClientTarget = false;
+        if (auto it = layerRequests.find(hwcLayer.get()); it != layerRequests.end()) {
+            auto request = it->second;
+            if (request == HWC2::LayerRequest::ClearClientTarget) {
+                state.clearClientTarget = true;
+            } else {
                 LOG_DISPLAY_ERROR(displayId,
-                                  ("Unknown layer request " + to_string(layerRequests[&*hwcLayer]))
-                                          .c_str());
+                                  ("Unknown layer request " + to_string(request)).c_str());
             }
-            compositionInfo.hwc.clearClientTarget = false;
-            compositionInfo.layer->mLayer->setClearClientTarget(displayId, false);
         }
     }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index f42f860..ca59a26 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -45,6 +45,10 @@
 class Composer;
 } // namespace Hwc2
 
+namespace compositionengine {
+class Output;
+} // namespace compositionengine
+
 class HWComposer {
 public:
     virtual ~HWComposer();
@@ -68,8 +72,7 @@
     virtual void destroyLayer(DisplayId displayId, HWC2::Layer* layer) = 0;
 
     // Asks the HAL what it can do
-    virtual status_t prepare(DisplayId displayId,
-                             std::vector<CompositionInfo>& compositionData) = 0;
+    virtual status_t prepare(DisplayId displayId, const compositionengine::Output&) = 0;
 
     virtual status_t setClientTarget(DisplayId displayId, uint32_t slot,
                                      const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
@@ -205,7 +208,7 @@
     void destroyLayer(DisplayId displayId, HWC2::Layer* layer) override;
 
     // Asks the HAL what it can do
-    status_t prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData) override;
+    status_t prepare(DisplayId displayId, const compositionengine::Output&) override;
 
     status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp<Fence>& acquireFence,
                              const sp<GraphicBuffer>& target, ui::Dataspace dataspace) override;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 646402c..b7aa5a5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -24,44 +24,42 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <algorithm>
+#include <mutex>
 
 #include <android-base/stringprintf.h>
-
+#include <compositionengine/Display.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <cutils/compiler.h>
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
-
+#include <gui/BufferItem.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/Surface.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/DebugUtils.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/NativeHandle.h>
 #include <utils/StopWatch.h>
 #include <utils/Trace.h>
 
-#include <ui/DebugUtils.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/PixelFormat.h>
-
-#include <gui/BufferItem.h>
-#include <gui/LayerDebugInfo.h>
-#include <gui/Surface.h>
-
 #include "BufferLayer.h"
 #include "ColorLayer.h"
 #include "Colorizer.h"
 #include "DisplayDevice.h"
+#include "DisplayHardware/HWComposer.h"
 #include "Layer.h"
+#include "LayerProtoHelper.h"
 #include "LayerRejecter.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
-
-#include "DisplayHardware/HWComposer.h"
 #include "TimeStats/TimeStats.h"
 
-#include <renderengine/RenderEngine.h>
-
-#include <mutex>
-#include "LayerProtoHelper.h"
-
 #define DEBUG_RESIZE 0
 
 namespace android {
@@ -128,8 +126,6 @@
 
     mFrameTracker.logAndResetStats(mName);
 
-    destroyAllHwcLayersPlusChildren();
-
     mFlinger->onLayerDestroyed();
 }
 
@@ -211,52 +207,18 @@
 // h/w composer set-up
 // ---------------------------------------------------------------------------
 
-bool Layer::createHwcLayer(HWComposer* hwc, DisplayId displayId) {
-    LOG_ALWAYS_FATAL_IF(hasHwcLayer(displayId), "Already have a layer for display %s",
-                        to_string(displayId).c_str());
-    auto layer = std::shared_ptr<HWC2::Layer>(
-            hwc->createLayer(displayId),
-            [hwc, displayId](HWC2::Layer* layer) {
-               hwc->destroyLayer(displayId, layer); });
-    if (!layer) {
-        return false;
-    }
-    LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers[displayId];
-    hwcInfo.hwc = hwc;
-    hwcInfo.layer = layer;
-    layer->setLayerDestroyedListener(
-            [this, displayId](HWC2::Layer* /*layer*/) { getBE().mHwcLayers.erase(displayId); });
-    return true;
+bool Layer::hasHwcLayer(const sp<const DisplayDevice>& displayDevice) {
+    auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    LOG_FATAL_IF(!outputLayer);
+    return outputLayer->getState().hwc && (*outputLayer->getState().hwc).hwcLayer != nullptr;
 }
 
-bool Layer::destroyHwcLayer(DisplayId displayId) {
-    if (!hasHwcLayer(displayId)) {
-        return false;
+HWC2::Layer* Layer::getHwcLayer(const sp<const DisplayDevice>& displayDevice) {
+    auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    if (!outputLayer || !outputLayer->getState().hwc) {
+        return nullptr;
     }
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
-    LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr, "Attempt to destroy null layer");
-    LOG_ALWAYS_FATAL_IF(hwcInfo.hwc == nullptr, "Missing HWComposer");
-    hwcInfo.layer = nullptr;
-
-    return true;
-}
-
-void Layer::destroyHwcLayersForAllDisplays() {
-    size_t numLayers = getBE().mHwcLayers.size();
-    for (size_t i = 0; i < numLayers; ++i) {
-        LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.empty(), "destroyAllHwcLayers failed");
-        destroyHwcLayer(getBE().mHwcLayers.begin()->first);
-    }
-}
-
-void Layer::destroyAllHwcLayersPlusChildren() {
-    destroyHwcLayersForAllDisplays();
-    LOG_ALWAYS_FATAL_IF(!getBE().mHwcLayers.empty(),
-                        "All hardware composer layers should have been destroyed");
-
-    for (const sp<Layer>& child : mDrawingChildren) {
-        child->destroyAllHwcLayersPlusChildren();
-    }
+    return (*outputLayer->getState().hwc).hwcLayer.get();
 }
 
 Rect Layer::getContentCrop() const {
@@ -266,9 +228,9 @@
     if (!mCurrentCrop.isEmpty()) {
         // if the buffer crop is defined, we use that
         crop = mCurrentCrop;
-    } else if (getBE().compositionInfo.mBuffer != nullptr) {
+    } else if (mActiveBuffer != nullptr) {
         // otherwise we use the whole buffer
-        crop = getBE().compositionInfo.mBuffer->getBounds();
+        crop = mActiveBuffer->getBounds();
     } else {
         // if we don't have a buffer yet, we use an empty/invalid crop
         crop.makeInvalid();
@@ -294,80 +256,83 @@
     return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
 }
 
-Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
-    const State& s(getDrawingState());
-    Region transparentRegion = reduceTransparentRegion ? getActiveTransparentRegion(s) : Region();
-    FloatRect bounds = computeBounds(transparentRegion);
+Rect Layer::getScreenBounds(bool reduceTransparentRegion) const {
+    if (!reduceTransparentRegion) {
+        return Rect{mScreenBounds};
+    }
+
+    FloatRect bounds = getBounds();
     ui::Transform t = getTransform();
     // Transform to screen space.
     bounds = t.transform(bounds);
     return Rect{bounds};
 }
 
-FloatRect Layer::computeBounds() const {
+FloatRect Layer::getBounds() const {
     const State& s(getDrawingState());
-    return computeBounds(getActiveTransparentRegion(s));
+    return getBounds(getActiveTransparentRegion(s));
 }
 
-FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
-    const State& s(getDrawingState());
-    Rect bounds = getCroppedBufferSize(s);
-    FloatRect floatBounds = bounds.toFloatRect();
-    if (bounds.isValid()) {
-        // Layer has bounds. Pass in our bounds as a special case. Then pass on to our parents so
-        // that they can clip it.
-        floatBounds = cropChildBounds(floatBounds);
-    } else {
-        // Layer does not have bounds, so we fill to our parent bounds. This is done by getting our
-        // parent bounds and inverting the transform to get the maximum bounds we can have that
-        // will fit within our parent bounds.
-        const auto& p = mDrawingParent.promote();
-        if (p != nullptr) {
-            ui::Transform t = s.active_legacy.transform;
-            // When calculating the parent bounds for purposes of clipping, we don't need to
-            // constrain the parent to its transparent region. The transparent region is an
-            // optimization based on the buffer contents of the layer, but does not affect the
-            // space allocated to it by policy, and thus children should be allowed to extend into
-            // the parent's transparent region.
-            // One of the main uses is a parent window with a child sitting behind the parent
-            // window, marked by a transparent region. When computing the parent bounds from the
-            // parent's perspective we pass in the transparent region to reduce buffer allocation
-            // size. When computing the parent bounds from the child's perspective, we pass in an
-            // empty transparent region in order to extend into the the parent bounds.
-            floatBounds = p->computeBounds(Region());
-            // Transform back to layer space.
-            floatBounds = t.inverse().transform(floatBounds);
-        }
-    }
-
+FloatRect Layer::getBounds(const Region& activeTransparentRegion) const {
     // Subtract the transparent region and snap to the bounds.
-    return reduce(floatBounds, activeTransparentRegion);
+    return reduce(mBounds, activeTransparentRegion);
 }
 
-FloatRect Layer::cropChildBounds(const FloatRect& childBounds) const {
+ui::Transform Layer::getTransformWithScale() const {
+    // If the layer is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g.
+    // it isFixedSize) then there may be additional scaling not accounted
+    // for in the transform. We need to mirror this scaling to child surfaces
+    // or we will break the contract where WM can treat child surfaces as
+    // pixels in the parent surface.
+    if (!isFixedSize() || !mActiveBuffer) {
+        return mEffectiveTransform;
+    }
+
+    int bufferWidth;
+    int bufferHeight;
+    if ((mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
+        bufferWidth = mActiveBuffer->getWidth();
+        bufferHeight = mActiveBuffer->getHeight();
+    } else {
+        bufferHeight = mActiveBuffer->getWidth();
+        bufferWidth = mActiveBuffer->getHeight();
+    }
+    float sx = getActiveWidth(getDrawingState()) / static_cast<float>(bufferWidth);
+    float sy = getActiveHeight(getDrawingState()) / static_cast<float>(bufferHeight);
+    ui::Transform extraParentScaling;
+    extraParentScaling.set(sx, 0, 0, sy);
+    return mEffectiveTransform * extraParentScaling;
+}
+
+void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform) {
     const State& s(getDrawingState());
-    Rect bounds = getCroppedBufferSize(s);
-    FloatRect croppedBounds = childBounds;
 
-    // If the layer has bounds, then crop the passed in child bounds and pass
-    // it to our parents so they can crop it as well. If the layer has no bounds,
-    // then pass on the child bounds.
-    if (bounds.isValid()) {
-        croppedBounds = croppedBounds.intersect(bounds.toFloatRect());
-    }
+    // Calculate effective layer transform
+    mEffectiveTransform = parentTransform * getActiveTransform(s);
 
-    const auto& p = mDrawingParent.promote();
-    if (p != nullptr) {
-        // Transform to parent space and allow parent layer to crop the
-        // child bounds as well.
-        ui::Transform t = s.active_legacy.transform;
-        croppedBounds = t.transform(croppedBounds);
-        croppedBounds = p->cropChildBounds(croppedBounds);
-        croppedBounds = t.inverse().transform(croppedBounds);
+    // Transform parent bounds to layer space
+    parentBounds = getActiveTransform(s).inverse().transform(parentBounds);
+
+    // Calculate display frame
+    mSourceBounds = computeSourceBounds(parentBounds);
+
+    // Calculate bounds by croping diplay frame with layer crop and parent bounds
+    FloatRect bounds = mSourceBounds;
+    const Rect layerCrop = getCrop(s);
+    if (!layerCrop.isEmpty()) {
+        bounds = mSourceBounds.intersect(layerCrop.toFloatRect());
     }
-    return croppedBounds;
+    bounds = bounds.intersect(parentBounds);
+
+    mBounds = bounds;
+    mScreenBounds = mEffectiveTransform.transform(mBounds);
+    for (const sp<Layer>& child : mDrawingChildren) {
+        child->computeBounds(mBounds, getTransformWithScale());
+    }
 }
 
+
+
 Rect Layer::getCroppedBufferSize(const State& s) const {
     Rect size = getBufferSize(s);
     Rect crop = getCrop(s);
@@ -389,7 +354,7 @@
     // if there are no window scaling involved, this operation will map to full
     // pixels in the buffer.
 
-    FloatRect activeCropFloat = computeBounds();
+    FloatRect activeCropFloat = getBounds();
     ui::Transform t = getTransform();
     // Transform to screen space.
     activeCropFloat = t.transform(activeCropFloat);
@@ -418,7 +383,8 @@
     win.top -= roundedCornersCrop.top;
     win.bottom -= roundedCornersCrop.top;
 
-    renderengine::Mesh::VertexArray<vec2> cropCoords(getBE().mMesh.getCropCoordArray<vec2>());
+    renderengine::Mesh::VertexArray<vec2> cropCoords(
+            getCompositionLayer()->editState().reMesh.getCropCoordArray<vec2>());
     cropCoords[0] = vec2(win.left, win.top);
     cropCoords[1] = vec2(win.left, win.top + win.getHeight());
     cropCoords[2] = vec2(win.right, win.top + win.getHeight());
@@ -491,19 +457,27 @@
 }
 
 void Layer::setGeometry(const sp<const DisplayDevice>& display, uint32_t z) {
-    const auto displayId = display->getId();
-    LOG_ALWAYS_FATAL_IF(!displayId);
-    RETURN_IF_NO_HWC_LAYER(*displayId);
-    auto& hwcInfo = getBE().mHwcLayers[*displayId];
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    LOG_FATAL_IF(!outputLayer->getState().hwc);
+    auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
 
-    // enable this layer
-    hwcInfo.forceClientComposition = false;
-
-    if (isSecure() && !display->isSecure()) {
-        hwcInfo.forceClientComposition = true;
+    if (!hasHwcLayer(display)) {
+        ALOGE("[%s] failed to setGeometry: no HWC layer found (%s)", mName.string(),
+              display->getDebugName().c_str());
+        return;
     }
 
-    auto& hwcLayer = hwcInfo.layer;
+    LOG_FATAL_IF(!getCompositionLayer());
+    auto& commonCompositionState = getCompositionLayer()->editState().frontEnd;
+    auto& compositionState = outputLayer->editState();
+
+    // enable this layer
+    compositionState.forceClientComposition = false;
+
+    if (isSecure() && !display->isSecure()) {
+        compositionState.forceClientComposition = true;
+    }
 
     // this gives us only the "orientation" component of the transform
     const State& s(getDrawingState());
@@ -519,7 +493,7 @@
              " %s (%d)",
              mName.string(), to_string(blendMode).c_str(), to_string(error).c_str(),
              static_cast<int32_t>(error));
-    getBE().compositionInfo.hwc.blendMode = blendMode;
+    commonCompositionState.blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
 
     // apply the layer's transform, followed by the display's global transform
     // here we're guaranteed that the layer's transform preserves rects
@@ -550,9 +524,9 @@
                 Rect(activeCrop.right, activeCrop.top, bufferSize.getWidth(), activeCrop.bottom));
     }
 
-    // computeBounds returns a FloatRect to provide more accuracy during the
+    // getBounds returns a FloatRect to provide more accuracy during the
     // transformation. We then round upon constructing 'frame'.
-    Rect frame{t.transform(computeBounds(activeTransparentRegion))};
+    Rect frame{t.transform(getBounds(activeTransparentRegion))};
     if (!frame.intersect(display->getViewport(), &frame)) {
         frame.clear();
     }
@@ -564,9 +538,8 @@
               transformedFrame.left, transformedFrame.top, transformedFrame.right,
               transformedFrame.bottom, to_string(error).c_str(), static_cast<int32_t>(error));
     } else {
-        hwcInfo.displayFrame = transformedFrame;
+        compositionState.displayFrame = transformedFrame;
     }
-    getBE().compositionInfo.hwc.displayFrame = transformedFrame;
 
     FloatRect sourceCrop = computeCrop(display);
     error = hwcLayer->setSourceCrop(sourceCrop);
@@ -576,9 +549,8 @@
               mName.string(), sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom,
               to_string(error).c_str(), static_cast<int32_t>(error));
     } else {
-        hwcInfo.sourceCrop = sourceCrop;
+        compositionState.sourceCrop = sourceCrop;
     }
-    getBE().compositionInfo.hwc.sourceCrop = sourceCrop;
 
     float alpha = static_cast<float>(getAlpha());
     error = hwcLayer->setPlaneAlpha(alpha);
@@ -586,12 +558,12 @@
              "[%s] Failed to set plane alpha %.3f: "
              "%s (%d)",
              mName.string(), alpha, to_string(error).c_str(), static_cast<int32_t>(error));
-    getBE().compositionInfo.hwc.alpha = alpha;
+    commonCompositionState.alpha = alpha;
 
     error = hwcLayer->setZOrder(z);
     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)", mName.string(), z,
              to_string(error).c_str(), static_cast<int32_t>(error));
-    getBE().compositionInfo.hwc.z = z;
+    compositionState.z = z;
 
     int type = s.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
     int appId = s.metadata.getInt32(METADATA_OWNER_UID, 0);
@@ -610,8 +582,8 @@
     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)", mName.string(),
              static_cast<int32_t>(error));
 
-    getBE().compositionInfo.hwc.type = type;
-    getBE().compositionInfo.hwc.appId = appId;
+    commonCompositionState.type = type;
+    commonCompositionState.appId = appId;
 
     /*
      * Transformations are applied in this order:
@@ -639,7 +611,7 @@
          * Here we cancel out the orientation component of the WM transform.
          * The scaling and translate components are already included in our bounds
          * computation so it's enough to just omit it in the composition.
-         * See comment in onDraw with ref to b/36727915 for why.
+         * See comment in BufferLayer::prepareClientLayer with ref to b/36727915 for why.
          */
         transform = ui::Transform(invTransform) * tr * bufferOrientation;
     }
@@ -648,40 +620,44 @@
     const uint32_t orientation = transform.getOrientation();
     if (orientation & ui::Transform::ROT_INVALID) {
         // we can only handle simple transformation
-        hwcInfo.forceClientComposition = true;
-        getBE().mHwcLayers[*displayId].compositionType = HWC2::Composition::Client;
+        compositionState.forceClientComposition = true;
+        (*compositionState.hwc).hwcCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
     } else {
         auto transform = static_cast<HWC2::Transform>(orientation);
-        hwcInfo.transform = transform;
         auto error = hwcLayer->setTransform(transform);
         ALOGE_IF(error != HWC2::Error::None,
                  "[%s] Failed to set transform %s: "
                  "%s (%d)",
                  mName.string(), to_string(transform).c_str(), to_string(error).c_str(),
                  static_cast<int32_t>(error));
-        getBE().compositionInfo.hwc.transform = transform;
+        compositionState.bufferTransform = static_cast<Hwc2::Transform>(transform);
     }
 }
 
-void Layer::forceClientComposition(DisplayId displayId) {
-    RETURN_IF_NO_HWC_LAYER(displayId);
-    getBE().mHwcLayers[displayId].forceClientComposition = true;
+void Layer::forceClientComposition(const sp<DisplayDevice>& display) {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    outputLayer->editState().forceClientComposition = true;
 }
 
-bool Layer::getForceClientComposition(DisplayId displayId) {
-    RETURN_IF_NO_HWC_LAYER(displayId, false);
-    return getBE().mHwcLayers[displayId].forceClientComposition;
+bool Layer::getForceClientComposition(const sp<DisplayDevice>& display) {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    return outputLayer->getState().forceClientComposition;
 }
 
 void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
-    const auto displayId = display->getId();
-    LOG_ALWAYS_FATAL_IF(!displayId);
-    if (!hasHwcLayer(*displayId) || getCompositionType(displayId) != HWC2::Composition::Cursor) {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+
+    if (!outputLayer->getState().hwc ||
+        (*outputLayer->getState().hwc).hwcCompositionType !=
+                Hwc2::IComposerClient::Composition::CURSOR) {
         return;
     }
 
     // This gives us only the "orientation" component of the transform
-    const State& s(getCurrentState());
+    const State& s(getDrawingState());
 
     // Apply the layer's transform, followed by the display's global transform
     // Here we're guaranteed that the layer's transform preserves rects
@@ -694,8 +670,7 @@
     auto position = displayTransform.transform(frame);
 
     auto error =
-            getBE().mHwcLayers[*displayId].layer->setCursorPosition(position.left, position.top);
-
+            (*outputLayer->getState().hwc).hwcLayer->setCursorPosition(position.left, position.top);
     ALOGE_IF(error != HWC2::Error::None,
              "[%s] Failed to set cursor position "
              "to (%d, %d): %s (%d)",
@@ -707,76 +682,100 @@
 // drawing...
 // ---------------------------------------------------------------------------
 
-void Layer::draw(const RenderArea& renderArea, const Region& clip) {
-    onDraw(renderArea, clip, false);
+bool Layer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+                               Region& clearRegion, renderengine::LayerSettings& layer) {
+    return prepareClientLayer(renderArea, clip, false, clearRegion, layer);
 }
 
-void Layer::draw(const RenderArea& renderArea, bool useIdentityTransform) {
-    onDraw(renderArea, Region(renderArea.getBounds()), useIdentityTransform);
+bool Layer::prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
+                               Region& clearRegion, renderengine::LayerSettings& layer) {
+    return prepareClientLayer(renderArea, Region(renderArea.getBounds()), useIdentityTransform,
+                              clearRegion, layer);
+}
+
+bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/,
+                               bool useIdentityTransform, Region& /*clearRegion*/,
+                               renderengine::LayerSettings& layer) {
+    FloatRect bounds = getBounds();
+    half alpha = getAlpha();
+    layer.geometry.boundaries = bounds;
+    if (useIdentityTransform) {
+        layer.geometry.positionTransform = mat4();
+    } else {
+        const ui::Transform transform = getTransform();
+        mat4 m;
+        m[0][0] = transform[0][0];
+        m[0][1] = transform[0][1];
+        m[0][3] = transform[0][2];
+        m[1][0] = transform[1][0];
+        m[1][1] = transform[1][1];
+        m[1][3] = transform[1][2];
+        m[3][0] = transform[2][0];
+        m[3][1] = transform[2][1];
+        m[3][3] = transform[2][2];
+        layer.geometry.positionTransform = m;
+    }
+
+    if (hasColorTransform()) {
+        layer.colorTransform = getColorTransform();
+    }
+
+    const auto roundedCornerState = getRoundedCornerState();
+    layer.geometry.roundedCornersRadius = roundedCornerState.radius;
+    layer.geometry.roundedCornersCrop = roundedCornerState.cropRect;
+
+    layer.alpha = alpha;
+    layer.sourceDataspace = mCurrentDataSpace;
+    return true;
 }
 
 void Layer::clearWithOpenGL(const RenderArea& renderArea, float red, float green, float blue,
                             float alpha) const {
     auto& engine(mFlinger->getRenderEngine());
-    computeGeometry(renderArea, getBE().mMesh, false);
+    computeGeometry(renderArea, getCompositionLayer()->editState().reMesh, false);
     engine.setupFillWithColor(red, green, blue, alpha);
-    engine.drawMesh(getBE().mMesh);
+    engine.drawMesh(getCompositionLayer()->getState().reMesh);
 }
 
 void Layer::clearWithOpenGL(const RenderArea& renderArea) const {
     clearWithOpenGL(renderArea, 0, 0, 0, 0);
 }
 
-void Layer::setCompositionType(DisplayId displayId, HWC2::Composition type, bool callIntoHwc) {
-    if (getBE().mHwcLayers.count(displayId) == 0) {
-        ALOGE("setCompositionType called without a valid HWC layer");
-        return;
-    }
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
-    auto& hwcLayer = hwcInfo.layer;
-    ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", (hwcLayer)->getId(), to_string(type).c_str(),
-          static_cast<int>(callIntoHwc));
-    if (hwcInfo.compositionType != type) {
+void Layer::setCompositionType(const sp<const DisplayDevice>& display,
+                               Hwc2::IComposerClient::Composition type) {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    LOG_FATAL_IF(!outputLayer->getState().hwc);
+    auto& compositionState = outputLayer->editState();
+
+    ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", ((*compositionState.hwc).hwcLayer)->getId(),
+          toString(type).c_str(), 1);
+    if ((*compositionState.hwc).hwcCompositionType != type) {
         ALOGV("    actually setting");
-        hwcInfo.compositionType = type;
-        if (callIntoHwc) {
-            auto error = (hwcLayer)->setCompositionType(type);
-            ALOGE_IF(error != HWC2::Error::None,
-                     "[%s] Failed to set "
-                     "composition type %s: %s (%d)",
-                     mName.string(), to_string(type).c_str(), to_string(error).c_str(),
-                     static_cast<int32_t>(error));
-        }
+        (*compositionState.hwc).hwcCompositionType = type;
+
+        auto error = (*compositionState.hwc)
+                             .hwcLayer->setCompositionType(static_cast<HWC2::Composition>(type));
+        ALOGE_IF(error != HWC2::Error::None,
+                 "[%s] Failed to set "
+                 "composition type %s: %s (%d)",
+                 mName.string(), toString(type).c_str(), to_string(error).c_str(),
+                 static_cast<int32_t>(error));
     }
 }
 
-HWC2::Composition Layer::getCompositionType(const std::optional<DisplayId>& displayId) const {
-    if (!displayId) {
-        // If we're querying the composition type for a display that does not
-        // have a HWC counterpart, then it will always be Client
-        return HWC2::Composition::Client;
-    }
-    if (getBE().mHwcLayers.count(*displayId) == 0) {
-        ALOGE("getCompositionType called with an invalid HWC layer");
-        return HWC2::Composition::Invalid;
-    }
-    return getBE().mHwcLayers.at(*displayId).compositionType;
+Hwc2::IComposerClient::Composition Layer::getCompositionType(
+        const sp<const DisplayDevice>& display) const {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    return outputLayer->getState().hwc ? (*outputLayer->getState().hwc).hwcCompositionType
+                                       : Hwc2::IComposerClient::Composition::CLIENT;
 }
 
-void Layer::setClearClientTarget(DisplayId displayId, bool clear) {
-    if (getBE().mHwcLayers.count(displayId) == 0) {
-        ALOGE("setClearClientTarget called without a valid HWC layer");
-        return;
-    }
-    getBE().mHwcLayers[displayId].clearClientTarget = clear;
-}
-
-bool Layer::getClearClientTarget(DisplayId displayId) const {
-    if (getBE().mHwcLayers.count(displayId) == 0) {
-        ALOGE("getClearClientTarget called without a valid HWC layer");
-        return false;
-    }
-    return getBE().mHwcLayers.at(displayId).clearClientTarget;
+bool Layer::getClearClientTarget(const sp<const DisplayDevice>& display) const {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    return outputLayer->getState().clearClientTarget;
 }
 
 bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) {
@@ -802,7 +801,7 @@
                             renderengine::Mesh& mesh,
                             bool useIdentityTransform) const {
     const ui::Transform renderAreaTransform(renderArea.getTransform());
-    FloatRect win = computeBounds();
+    FloatRect win = getBounds();
 
     vec2 lt = vec2(win.left, win.top);
     vec2 lb = vec2(win.left, win.bottom);
@@ -995,9 +994,9 @@
     const bool resizePending =
             ((stateToCommit->requested_legacy.w != stateToCommit->active_legacy.w) ||
              (stateToCommit->requested_legacy.h != stateToCommit->active_legacy.h)) &&
-            (getBE().compositionInfo.mBuffer != nullptr);
+            (mActiveBuffer != nullptr);
     if (!isFixedSize()) {
-        if (resizePending && getBE().compositionInfo.hwc.sidebandStream == nullptr) {
+        if (resizePending && mSidebandStream == nullptr) {
             flags |= eDontUpdateGeometryState;
         }
     }
@@ -1039,13 +1038,18 @@
     ATRACE_CALL();
 
     if (mLayerDetached) {
-        return 0;
+        return flags;
+    }
+
+    if (mChildrenChanged) {
+        flags |= eVisibleRegion;
+        mChildrenChanged = false;
     }
 
     pushPendingState();
     State c = getCurrentState();
     if (!applyPendingStates(&c)) {
-        return 0;
+        return flags;
     }
 
     flags = doTransactionResize(flags, &c);
@@ -1067,11 +1071,6 @@
         mNeedsFiltering = (!getActiveTransform(c).preserveRects() || type >= ui::Transform::SCALE);
     }
 
-    if (mChildrenChanged) {
-        flags |= eVisibleRegion;
-        mChildrenChanged = false;
-    }
-
     // If the layer is hidden, signal and clear out all local sync points so
     // that transactions for layers depending on this layer's frames becoming
     // visible are not blocked
@@ -1241,7 +1240,12 @@
 bool Layer::setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace) {
     if (!mCurrentState.bgColorLayer && alpha == 0) {
         return false;
-    } else if (!mCurrentState.bgColorLayer && alpha != 0) {
+    }
+    mCurrentState.sequence++;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+
+    if (!mCurrentState.bgColorLayer && alpha != 0) {
         // create background color layer if one does not yet exist
         uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor;
         const String8& name = mName + "BackgroundColorLayer";
@@ -1486,8 +1490,9 @@
     result.append("-----------------------------\n");
 }
 
-void Layer::miniDump(std::string& result, DisplayId displayId) const {
-    if (!hasHwcLayer(displayId)) {
+void Layer::miniDump(std::string& result, const sp<DisplayDevice>& displayDevice) const {
+    auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    if (!outputLayer) {
         return;
     }
 
@@ -1505,26 +1510,24 @@
     StringAppendF(&result, " %s\n", name.c_str());
 
     const State& layerState(getDrawingState());
-    const LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers.at(displayId);
+    const auto& compositionState = outputLayer->getState();
+
     if (layerState.zOrderRelativeOf != nullptr || mDrawingParent != nullptr) {
         StringAppendF(&result, "  rel %6d | ", layerState.z);
     } else {
         StringAppendF(&result, "  %10d | ", layerState.z);
     }
-    StringAppendF(&result, "%10s | ", to_string(getCompositionType(displayId)).c_str());
-    StringAppendF(&result, "%10s | ", to_string(hwcInfo.transform).c_str());
-    const Rect& frame = hwcInfo.displayFrame;
+    StringAppendF(&result, "%10s | ", toString(getCompositionType(displayDevice)).c_str());
+    StringAppendF(&result, "%10s | ",
+                  toString(getCompositionLayer() ? compositionState.bufferTransform
+                                                 : static_cast<Hwc2::Transform>(0))
+                          .c_str());
+    const Rect& frame = compositionState.displayFrame;
     StringAppendF(&result, "%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
-    const FloatRect& crop = hwcInfo.sourceCrop;
+    const FloatRect& crop = compositionState.sourceCrop;
     StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right,
                   crop.bottom);
 
-    result.append("- - - - - - - - - - - - - - - -\n");
-
-    std::string compositionInfoStr;
-    getBE().compositionInfo.dump(compositionInfoStr, "compositionInfo");
-    result.append(compositionInfoStr);
-
     result.append("- - - - - - - - - - - - - - - -");
     result.append("- - - - - - - - - - - - - - - -");
     result.append("- - - - - - - - - - - - - - -\n");
@@ -1593,6 +1596,7 @@
 
 void Layer::addChild(const sp<Layer>& layer) {
     mChildrenChanged = true;
+    setTransactionFlags(eTransactionNeeded);
 
     mCurrentChildren.add(layer);
     layer->setParent(this);
@@ -1600,6 +1604,7 @@
 
 ssize_t Layer::removeChild(const sp<Layer>& layer) {
     mChildrenChanged = true;
+    setTransactionFlags(eTransactionNeeded);
 
     layer->setParent(nullptr);
     return mCurrentChildren.remove(layer);
@@ -1632,6 +1637,7 @@
 void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
     for (const sp<Layer>& child : mDrawingChildren) {
         child->mDrawingParent = newParent;
+        child->computeBounds(newParent->mBounds, newParent->getTransformWithScale());
     }
 }
 
@@ -1959,34 +1965,7 @@
 }
 
 ui::Transform Layer::getTransform() const {
-    ui::Transform t;
-    const auto& p = mDrawingParent.promote();
-    if (p != nullptr) {
-        t = p->getTransform();
-
-        // If the parent is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g.
-        // it isFixedSize) then there may be additional scaling not accounted
-        // for in the transform. We need to mirror this scaling in child surfaces
-        // or we will break the contract where WM can treat child surfaces as
-        // pixels in the parent surface.
-        if (p->isFixedSize() && p->getBE().compositionInfo.mBuffer != nullptr) {
-            int bufferWidth;
-            int bufferHeight;
-            if ((p->mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
-                bufferWidth = p->getBE().compositionInfo.mBuffer->getWidth();
-                bufferHeight = p->getBE().compositionInfo.mBuffer->getHeight();
-            } else {
-                bufferHeight = p->getBE().compositionInfo.mBuffer->getWidth();
-                bufferWidth = p->getBE().compositionInfo.mBuffer->getHeight();
-            }
-            float sx = p->getActiveWidth(p->getDrawingState()) / static_cast<float>(bufferWidth);
-            float sy = p->getActiveHeight(p->getDrawingState()) / static_cast<float>(bufferHeight);
-            ui::Transform extraParentScaling;
-            extraParentScaling.set(sx, 0, 0, sy);
-            t = t * extraParentScaling;
-        }
-    }
-    return t * getActiveTransform(getDrawingState());
+    return mEffectiveTransform;
 }
 
 half Layer::getAlpha() const {
@@ -2018,7 +1997,7 @@
         }
     }
     const float radius = getDrawingState().cornerRadius;
-    return radius > 0 ? RoundedCornerState(computeBounds(), radius) : RoundedCornerState();
+    return radius > 0 ? RoundedCornerState(getBounds(), radius) : RoundedCornerState();
 }
 
 void Layer::commitChildList() {
@@ -2100,15 +2079,18 @@
     auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
     if (parent != nullptr) {
         layerInfo->set_parent(parent->sequence);
+    } else {
+        layerInfo->set_parent(-1);
     }
 
     auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
     if (zOrderRelativeOf != nullptr) {
         layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
+    } else {
+        layerInfo->set_z_order_relative_of(-1);
     }
 
-    // XXX getBE().compositionInfo.mBuffer is not protected
-    auto buffer = getBE().compositionInfo.mBuffer;
+    auto buffer = mActiveBuffer;
     if (buffer != nullptr) {
         LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer());
         LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
@@ -2133,27 +2115,35 @@
     for (const auto& entry : state.metadata.mMap) {
         (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
     }
+    LayerProtoHelper::writeToProto(mEffectiveTransform, layerInfo->mutable_effective_transform());
+    LayerProtoHelper::writeToProto(mSourceBounds, layerInfo->mutable_source_bounds());
+    LayerProtoHelper::writeToProto(mScreenBounds, layerInfo->mutable_screen_bounds());
+    LayerProtoHelper::writeToProto(mBounds, layerInfo->mutable_bounds());
 }
 
-void Layer::writeToProto(LayerProto* layerInfo, DisplayId displayId) {
-    if (!hasHwcLayer(displayId)) {
+void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice) {
+    auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    if (!outputLayer) {
         return;
     }
 
     writeToProto(layerInfo, LayerVector::StateSet::Drawing);
 
-    const auto& hwcInfo = getBE().mHwcLayers.at(displayId);
+    const auto& compositionState = outputLayer->getState();
 
-    const Rect& frame = hwcInfo.displayFrame;
+    const Rect& frame = compositionState.displayFrame;
     LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
 
-    const FloatRect& crop = hwcInfo.sourceCrop;
+    const FloatRect& crop = compositionState.sourceCrop;
     LayerProtoHelper::writeToProto(crop, layerInfo->mutable_hwc_crop());
 
-    const int32_t transform = static_cast<int32_t>(hwcInfo.transform);
+    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>(hwcInfo.compositionType);
+    const int32_t compositionType =
+            static_cast<int32_t>(compositionState.hwc ? (*compositionState.hwc).hwcCompositionType
+                                                      : Hwc2::IComposerClient::Composition::CLIENT);
     layerInfo->set_hwc_composition_type(compositionType);
 
     if (std::strcmp(getTypeId(), "BufferLayer") == 0 &&
@@ -2204,7 +2194,7 @@
     // Position the touchable region relative to frame screen location and restrict it to frame
     // bounds.
     info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop);
-    info.visible = isVisible();
+    info.visible = canReceiveInput();
     return info;
 }
 
@@ -2216,6 +2206,15 @@
     return nullptr;
 }
 
+bool Layer::canReceiveInput() const {
+    return isVisible();
+}
+
+compositionengine::OutputLayer* Layer::findOutputLayerForDisplay(
+        const sp<const DisplayDevice>& display) const {
+    return display->getCompositionDisplay()->getOutputLayerForLayer(getCompositionLayer().get());
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 367129a..fcec262 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -51,6 +51,7 @@
 #include "SurfaceFlinger.h"
 #include "TransactionCompletedThread.h"
 
+#include "DisplayHardware/ComposerHal.h"
 #include "DisplayHardware/HWComposer.h"
 #include "RenderArea.h"
 
@@ -70,6 +71,7 @@
 
 namespace compositionengine {
 class Layer;
+class OutputLayer;
 }
 
 namespace impl {
@@ -349,8 +351,15 @@
 
     void computeGeometry(const RenderArea& renderArea, renderengine::Mesh& mesh,
                          bool useIdentityTransform) const;
-    FloatRect computeBounds(const Region& activeTransparentRegion) const;
-    FloatRect computeBounds() const;
+    FloatRect getBounds(const Region& activeTransparentRegion) const;
+    FloatRect getBounds() const;
+
+    // Compute bounds for the layer and cache the results.
+    void computeBounds(FloatRect parentBounds, ui::Transform parentTransform);
+
+    // Get effective layer transform, taking into account all its parent transform with any
+    // scaling if the parent scaling more is not NATIVE_WINDOW_SCALING_MODE_FREEZE.
+    ui::Transform getTransformWithScale() const;
 
     int32_t getSequence() const { return sequence; }
 
@@ -387,6 +396,11 @@
     bool isHiddenByPolicy() const;
 
     /*
+     * Returns whether this layer can receive input.
+     */
+    virtual bool canReceiveInput() const;
+
+    /*
      * isProtected - true if the layer may contain protected content in the
      * GRALLOC_USAGE_PROTECTED sense.
      */
@@ -407,7 +421,7 @@
     void writeToProto(LayerProto* layerInfo,
                       LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
 
-    void writeToProto(LayerProto* layerInfo, DisplayId displayId);
+    void writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice);
 
     virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
     virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
@@ -421,11 +435,9 @@
     virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
 
 protected:
-    /*
-     * onDraw - draws the surface.
-     */
-    virtual void onDraw(const RenderArea& renderArea, const Region& clip,
-                        bool useIdentityTransform) = 0;
+    virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+                                    bool useIdentityTransform, Region& clearRegion,
+                                    renderengine::LayerSettings& layer) = 0;
 
 public:
     virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
@@ -433,17 +445,19 @@
     virtual bool isHdrY410() const { return false; }
 
     void setGeometry(const sp<const DisplayDevice>& display, uint32_t z);
-    void forceClientComposition(DisplayId displayId);
-    bool getForceClientComposition(DisplayId displayId);
-    virtual void setPerFrameData(DisplayId displayId, const ui::Transform& transform,
-                                 const Rect& viewport, int32_t supportedPerFrameMetadata) = 0;
+    void forceClientComposition(const sp<DisplayDevice>& display);
+    bool getForceClientComposition(const sp<DisplayDevice>& display);
+    virtual void setPerFrameData(const sp<const DisplayDevice>& display,
+                                 const ui::Transform& transform, const Rect& viewport,
+                                 int32_t supportedPerFrameMetadata) = 0;
 
     // callIntoHwc exists so we can update our local state and call
     // acceptDisplayChanges without unnecessarily updating the device's state
-    void setCompositionType(DisplayId displayId, HWC2::Composition type, bool callIntoHwc = true);
-    HWC2::Composition getCompositionType(const std::optional<DisplayId>& displayId) const;
-    void setClearClientTarget(DisplayId displayId, bool clear);
-    bool getClearClientTarget(DisplayId displayId) const;
+    void setCompositionType(const sp<const DisplayDevice>& display,
+                            Hwc2::IComposerClient::Composition type);
+    Hwc2::IComposerClient::Composition getCompositionType(
+            const sp<const DisplayDevice>& display) const;
+    bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
     void updateCursorPosition(const sp<const DisplayDevice>& display);
 
     /*
@@ -475,11 +489,14 @@
     virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
 
     /*
-     * draw - performs some global clipping optimizations
-     * and calls onDraw().
+     * prepareClientLayer - populates a renderengine::LayerSettings to passed to
+     * RenderEngine::drawLayers. Returns true if the layer can be used, and
+     * false otherwise.
      */
-    void draw(const RenderArea& renderArea, const Region& clip);
-    void draw(const RenderArea& renderArea, bool useIdentityTransform);
+    bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, Region& clearRegion,
+                            renderengine::LayerSettings& layer);
+    bool prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
+                            Region& clearRegion, renderengine::LayerSettings& layer);
 
     /*
      * doTransaction - process the transaction. This is a good place to figure
@@ -517,8 +534,7 @@
      * operation, so this should be set only if needed). Typically this is used
      * to figure out if the content or size of a surface has changed.
      */
-    virtual Region latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
-                               const sp<Fence>& /*releaseFence*/) {
+    virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) {
         return {};
     }
 
@@ -554,27 +570,8 @@
 
     // -----------------------------------------------------------------------
 
-    bool createHwcLayer(HWComposer* hwc, DisplayId displayId);
-    bool destroyHwcLayer(DisplayId displayId);
-    void destroyHwcLayersForAllDisplays();
-    void destroyAllHwcLayersPlusChildren();
-
-    bool hasHwcLayer(DisplayId displayId) const { return getBE().mHwcLayers.count(displayId) > 0; }
-
-    HWC2::Layer* getHwcLayer(DisplayId displayId) {
-        if (!hasHwcLayer(displayId)) {
-            return nullptr;
-        }
-        return getBE().mHwcLayers[displayId].layer.get();
-    }
-
-    bool setHwcLayer(DisplayId displayId) {
-        if (!hasHwcLayer(displayId)) {
-            return false;
-        }
-        getBE().compositionInfo.hwc.hwcLayer = getBE().mHwcLayers[displayId].layer;
-        return true;
-    }
+    bool hasHwcLayer(const sp<const DisplayDevice>& displayDevice);
+    HWC2::Layer* getHwcLayer(const sp<const DisplayDevice>& displayDevice);
 
     // -----------------------------------------------------------------------
     void clearWithOpenGL(const RenderArea& renderArea) const;
@@ -587,7 +584,7 @@
 
     /* always call base class first */
     static void miniDumpHeader(std::string& result);
-    void miniDump(std::string& result, DisplayId displayId) const;
+    void miniDump(std::string& result, const sp<DisplayDevice>& display) const;
     void dumpFrameStats(std::string& result) const;
     void dumpFrameEvents(std::string& result);
     void clearFrameStats();
@@ -637,7 +634,7 @@
     ssize_t removeChild(const sp<Layer>& layer);
     sp<Layer> getParent() const { return mCurrentParent.promote(); }
     bool hasParent() const { return getParent() != nullptr; }
-    Rect computeScreenBounds(bool reduceTransparentRegion = true) const;
+    Rect getScreenBounds(bool reduceTransparentRegion = true) const;
     bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
     bool setChildRelativeLayer(const sp<Layer>& childLayer,
             const sp<IBinder>& relativeToHandle, int32_t relativeZ);
@@ -654,6 +651,18 @@
      */
     virtual Rect getBufferSize(const Layer::State&) const { return Rect::INVALID_RECT; }
 
+    /**
+     * Returns the source bounds. If the bounds are not defined, it is inferred from the
+     * buffer size. Failing that, the bounds are determined from the passed in parent bounds.
+     * For the root layer, this is the display viewport size.
+     */
+    virtual FloatRect computeSourceBounds(const FloatRect& parentBounds) const {
+        return parentBounds;
+    }
+
+    compositionengine::OutputLayer* findOutputLayerForDisplay(
+            const sp<const DisplayDevice>& display) const;
+
 protected:
     // constant
     sp<SurfaceFlinger> mFlinger;
@@ -810,7 +819,14 @@
     FenceTimeline mReleaseTimeline;
 
     // main thread
+    sp<NativeHandle> mSidebandStream;
+    // Active buffer fields
     sp<GraphicBuffer> mActiveBuffer;
+    sp<Fence> mActiveBufferFence;
+    // False if the buffer and its contents have been previously used for GPU
+    // composition, true otherwise.
+    bool mIsActiveBufferUpdatedForGpu = true;
+
     ui::Dataspace mCurrentDataSpace = ui::Dataspace::UNKNOWN;
     Rect mCurrentCrop;
     uint32_t mCurrentTransform{0};
@@ -866,14 +882,6 @@
                                        const LayerVector::Visitor& visitor);
     LayerVector makeChildrenTraversalList(LayerVector::StateSet stateSet,
                                           const std::vector<Layer*>& layersInTree);
-
-    /**
-     * Retuns the child bounds in layer space cropped to its bounds as well all its parent bounds.
-     * The cropped bounds must be transformed back from parent layer space to child layer space by
-     * applying the inverse of the child's transformation.
-     */
-    FloatRect cropChildBounds(const FloatRect& childBounds) const;
-
     /**
      * Returns the cropped buffer size or the layer crop if the layer has no buffer. Return
      * INVALID_RECT if the layer has no buffer and no crop.
@@ -881,15 +889,30 @@
      * bounds are constrained by its parent bounds.
      */
     Rect getCroppedBufferSize(const Layer::State& s) const;
+
+    // Cached properties computed from drawing state
+    // Effective transform taking into account parent transforms and any parent scaling.
+    ui::Transform mEffectiveTransform;
+
+    // Bounds of the layer before any transformation is applied and before it has been cropped
+    // by its parents.
+    FloatRect mSourceBounds;
+
+    // Bounds of the layer in layer space. This is the mSourceBounds cropped by its layer crop and
+    // its parent bounds.
+    FloatRect mBounds;
+
+    // Layer bounds in screen space.
+    FloatRect mScreenBounds;
 };
 
 } // namespace android
 
-#define RETURN_IF_NO_HWC_LAYER(displayId, ...)                                         \
+#define RETURN_IF_NO_HWC_LAYER(displayDevice, ...)                                     \
     do {                                                                               \
-        if (!hasHwcLayer(displayId)) {                                                 \
+        if (!hasHwcLayer(displayDevice)) {                                             \
             ALOGE("[%s] %s failed: no HWC layer found for display %s", mName.string(), \
-                  __FUNCTION__, to_string(displayId).c_str());                         \
+                  __FUNCTION__, displayDevice->getDebugName().c_str());                \
             return __VA_ARGS__;                                                        \
         }                                                                              \
     } while (false)
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
index e39babe..9f63440 100644
--- a/services/surfaceflinger/LayerBE.cpp
+++ b/services/surfaceflinger/LayerBE.cpp
@@ -21,45 +21,14 @@
 
 #include "Layer.h"
 
-#include <android-base/stringprintf.h>
-#include <renderengine/RenderEngine.h>
-
-#include <string>
-
-namespace {
-
-const char* getCompositionName(HWC2::Composition compositionType) {
-    switch (compositionType) {
-        case HWC2::Composition::Invalid:
-            return "Invalid";
-        case HWC2::Composition::Client:
-            return "Client";
-        case HWC2::Composition::Device:
-            return "Device";
-        case HWC2::Composition::SolidColor:
-            return "Solid Color";
-        case HWC2::Composition::Cursor:
-            return "Cursor";
-        case HWC2::Composition::Sideband:
-            return "Sideband";
-    }
-    return "Invalid";
-}
-
-}  // namespace anonymous
-
 namespace android {
 
-LayerBE::LayerBE(Layer* layer, std::string layerName)
-      : mLayer(layer),
-        mMesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2, 2) {
+LayerBE::LayerBE(Layer* layer, std::string layerName) : mLayer(layer) {
     compositionInfo.layer = std::make_shared<LayerBE>(*this);
     compositionInfo.layerName = layerName;
 }
 
-LayerBE::LayerBE(const LayerBE& layer)
-      : mLayer(layer.mLayer),
-        mMesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2, 2) {
+LayerBE::LayerBE(const LayerBE& layer) : mLayer(layer.mLayer) {
     compositionInfo.layer = layer.compositionInfo.layer;
     compositionInfo.layerName = layer.mLayer->getName().string();
 }
@@ -68,101 +37,4 @@
     mLayer->onLayerDisplayed(releaseFence);
 }
 
-void LayerBE::clear(renderengine::RenderEngine& engine) {
-    engine.setupFillWithColor(0, 0, 0, 0);
-    engine.drawMesh(mMesh);
-}
-
-void CompositionInfo::dump(const char* tag) const
-{
-    std::string logString;
-    dump(logString, tag);
-    ALOGV("%s", logString.c_str());
-}
-
-void CompositionInfo::dumpHwc(std::string& result, const char* tag) const {
-    if (tag == nullptr) {
-        result += base::StringPrintf("HWC parameters\n");
-    } else {
-        result += base::StringPrintf("[%s]HWC parameters\n", tag);
-    }
-
-    result += base::StringPrintf("\thwcLayer=%p\n", static_cast<HWC2::Layer*>(&*hwc.hwcLayer));
-    result += base::StringPrintf("\tfence=%p\n", hwc.fence.get());
-    result += base::StringPrintf("\tblendMode=%d\n", hwc.blendMode);
-    result += base::StringPrintf("\ttransform=%d\n", hwc.transform);
-    result += base::StringPrintf("\tz=%d\n", hwc.z);
-    result += base::StringPrintf("\ttype=%d\n", hwc.type);
-    result += base::StringPrintf("\tappId=%d\n", hwc.appId);
-    result += base::StringPrintf("\tdisplayFrame=%4d %4d %4d %4d\n", hwc.displayFrame.left,
-                                 hwc.displayFrame.top, hwc.displayFrame.right,
-                                 hwc.displayFrame.bottom);
-    result += base::StringPrintf("\talpha=%.3f", hwc.alpha);
-    result += base::StringPrintf("\tsourceCrop=%6.1f %6.1f %6.1f %6.1f\n", hwc.sourceCrop.left,
-                                 hwc.sourceCrop.top, hwc.sourceCrop.right, hwc.sourceCrop.bottom);
-
-    hwc.visibleRegion.dump(result, "visibleRegion");
-    hwc.surfaceDamage.dump(result, "surfaceDamage");
-
-    result += base::StringPrintf("\tcolor transform matrix:\n"
-                                 "\t\t[%f, %f, %f, %f,\n"
-                                 "\t\t %f, %f, %f, %f,\n"
-                                 "\t\t %f, %f, %f, %f,\n"
-                                 "\t\t %f, %f, %f, %f]\n",
-                                 hwc.colorTransform[0][0], hwc.colorTransform[1][0],
-                                 hwc.colorTransform[2][0], hwc.colorTransform[3][0],
-                                 hwc.colorTransform[0][1], hwc.colorTransform[1][1],
-                                 hwc.colorTransform[2][1], hwc.colorTransform[3][1],
-                                 hwc.colorTransform[0][2], hwc.colorTransform[1][2],
-                                 hwc.colorTransform[2][2], hwc.colorTransform[3][2],
-                                 hwc.colorTransform[0][3], hwc.colorTransform[1][3],
-                                 hwc.colorTransform[2][3], hwc.colorTransform[3][3]);
-}
-
-void CompositionInfo::dumpRe(std::string& result, const char* tag) const {
-    if (tag == nullptr) {
-        result += base::StringPrintf("RenderEngine parameters:\n");
-    } else {
-        result += base::StringPrintf("[%s]RenderEngine parameters:\n", tag);
-    }
-
-    result += base::StringPrintf("\tblackoutLayer=%d\n", re.blackoutLayer);
-    result += base::StringPrintf("\tclearArea=%d\n", re.clearArea);
-    result += base::StringPrintf("\tpreMultipliedAlpha=%d\n", re.preMultipliedAlpha);
-    result += base::StringPrintf("\topaque=%d\n", re.opaque);
-    result += base::StringPrintf("\tdisableTexture=%d\n", re.disableTexture);
-    result += base::StringPrintf("\tuseIdentityTransform=%d\n", re.useIdentityTransform);
-}
-
-void CompositionInfo::dump(std::string& result, const char* tag) const
-{
-    if (tag == nullptr) {
-        result += base::StringPrintf("CompositionInfo\n");
-    } else {
-        result += base::StringPrintf("[%s]CompositionInfo\n", tag);
-    }
-    result += base::StringPrintf("\tLayerName: %s\n", layerName.c_str());
-    result += base::StringPrintf("\tCompositionType: %s\n",
-                                 getCompositionName(compositionType));
-    result += base::StringPrintf("\tmBuffer = %p\n", mBuffer.get());
-    result += base::StringPrintf("\tmBufferSlot=%d\n", mBufferSlot);
-    result += base::StringPrintf("\tdisplayFrame=%4d %4d %4d %4d\n", hwc.displayFrame.left,
-                                 hwc.displayFrame.top, hwc.displayFrame.right,
-                                 hwc.displayFrame.bottom);
-    result += base::StringPrintf("\talpha=%f\n", hwc.alpha);
-    result += base::StringPrintf("\tsourceCrop=%6.1f %6.1f %6.1f %6.1f\n", hwc.sourceCrop.left,
-                                 hwc.sourceCrop.top, hwc.sourceCrop.right, hwc.sourceCrop.bottom);
-
-    switch (compositionType) {
-        case HWC2::Composition::Device:
-            dumpHwc(result, tag);
-            break;
-        case HWC2::Composition::Client:
-            dumpRe(result, tag);
-            break;
-        default:
-            break;
-    }
-}
-
 }; // namespace android
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index 6270efa..51f7857 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -17,18 +17,12 @@
 #pragma once
 
 #include <stdint.h>
-#include <sys/types.h>
+#include <string.h>
 
-#include <compositionengine/impl/HwcBufferCache.h>
-
-#include <renderengine/Mesh.h>
-#include <renderengine/RenderEngine.h>
-#include <renderengine/Texture.h>
-#include <ui/Region.h>
+#include <ui/Fence.h>
+#include <utils/StrongPointer.h>
 
 #include "DisplayHardware/DisplayIdentification.h"
-#include "DisplayHardware/HWComposer.h"
-#include "SurfaceFlinger.h"
 
 namespace android {
 
@@ -36,48 +30,10 @@
 
 struct CompositionInfo {
     std::string layerName;
-    HWC2::Composition compositionType;
-    bool firstClear = false;
-    sp<GraphicBuffer> mBuffer = nullptr;
-    int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
     std::shared_ptr<LayerBE> layer;
     struct {
-        std::shared_ptr<HWC2::Layer> hwcLayer;
         DisplayId displayId;
-        sp<Fence> fence;
-        HWC2::BlendMode blendMode = HWC2::BlendMode::Invalid;
-        Rect displayFrame;
-        float alpha;
-        FloatRect sourceCrop;
-        HWC2::Transform transform = HWC2::Transform::None;
-        int z;
-        int type;
-        int appId;
-        Region visibleRegion;
-        Region surfaceDamage;
-        sp<NativeHandle> sidebandStream;
-        ui::Dataspace dataspace;
-        hwc_color_t color;
-        bool clearClientTarget = false;
-        bool supportedPerFrameMetadata = false;
-        HdrMetadata hdrMetadata;
-        mat4 colorTransform;
     } hwc;
-    struct {
-        bool blackoutLayer = false;
-        bool clearArea = false;
-        bool preMultipliedAlpha = false;
-        bool opaque = false;
-        bool disableTexture = false;
-        half4 color;
-        bool useIdentityTransform = false;
-        bool Y410BT2020 = false;
-    } re;
-
-    void dump(const char* tag) const;
-    void dump(std::string& result, const char* tag = nullptr) const;
-    void dumpHwc(std::string& result, const char* tag = nullptr) const;
-    void dumpRe(std::string& result, const char* tag = nullptr) const;
 };
 
 class LayerBE {
@@ -96,41 +52,10 @@
     explicit LayerBE(const LayerBE& layer);
 
     void onLayerDisplayed(const sp<Fence>& releaseFence);
-    void clear(renderengine::RenderEngine& renderEngine);
-    renderengine::Mesh& getMesh() { return mMesh; }
 
     Layer*const mLayer;
+
 private:
-    // The mesh used to draw the layer in GLES composition mode
-    renderengine::Mesh mMesh;
-
-    // HWC items, accessed from the main thread
-    struct HWCInfo {
-        HWCInfo()
-              : hwc(nullptr),
-                layer(nullptr),
-                forceClientComposition(false),
-                compositionType(HWC2::Composition::Invalid),
-                clearClientTarget(false),
-                transform(HWC2::Transform::None) {}
-
-        HWComposer* hwc;
-        std::shared_ptr<HWC2::Layer> layer;
-        bool forceClientComposition;
-        HWC2::Composition compositionType;
-        bool clearClientTarget;
-        Rect displayFrame;
-        FloatRect sourceCrop;
-        compositionengine::impl::HwcBufferCache bufferCache;
-        HWC2::Transform transform;
-    };
-
-    // A layer can be attached to multiple displays when operating in mirror mode
-    // (a.k.a: when several displays are attached with equal layerStack). In this
-    // case we need to keep track. In non-mirror mode, a layer will have only one
-    // HWCInfo.
-    std::unordered_map<DisplayId, HWCInfo> mHwcLayers;
-
     CompositionInfo compositionInfo;
 };
 
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index dc2b300..ce0611c 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -1,3 +1,4 @@
+akrulec@google.com
 chaviw@google.com
 lpy@google.com
 marissaw@google.com
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
new file mode 100644
index 0000000..cbc7ada
--- /dev/null
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#undef LOG_TAG
+#define LOG_TAG "RegionSamplingThread"
+
+#include "RegionSamplingThread.h"
+
+#include <gui/IRegionSamplingListener.h>
+#include <utils/Trace.h>
+
+#include "DisplayDevice.h"
+#include "Layer.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+template <typename T>
+struct SpHash {
+    size_t operator()(const sp<T>& p) const { return std::hash<T*>()(p.get()); }
+};
+
+RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger) : mFlinger(flinger) {
+    std::lock_guard threadLock(mThreadMutex);
+    mThread = std::thread([this]() { threadMain(); });
+    pthread_setname_np(mThread.native_handle(), "RegionSamplingThread");
+}
+
+RegionSamplingThread::~RegionSamplingThread() {
+    {
+        std::lock_guard lock(mMutex);
+        mRunning = false;
+        mCondition.notify_one();
+    }
+
+    std::lock_guard threadLock(mThreadMutex);
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void RegionSamplingThread::addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+                                       const sp<IRegionSamplingListener>& listener) {
+    wp<Layer> stopLayer = stopLayerHandle != nullptr
+            ? static_cast<Layer::Handle*>(stopLayerHandle.get())->owner
+            : nullptr;
+
+    sp<IBinder> asBinder = IInterface::asBinder(listener);
+    asBinder->linkToDeath(this);
+    std::lock_guard lock(mMutex);
+    mDescriptors.emplace(wp<IBinder>(asBinder), Descriptor{samplingArea, stopLayer, listener});
+}
+
+void RegionSamplingThread::removeListener(const sp<IRegionSamplingListener>& listener) {
+    std::lock_guard lock(mMutex);
+    mDescriptors.erase(wp<IBinder>(IInterface::asBinder(listener)));
+}
+
+void RegionSamplingThread::sampleNow() {
+    std::lock_guard lock(mMutex);
+    mSampleRequested = true;
+    mCondition.notify_one();
+}
+
+void RegionSamplingThread::binderDied(const wp<IBinder>& who) {
+    std::lock_guard lock(mMutex);
+    mDescriptors.erase(who);
+}
+
+namespace {
+// Using Rec. 709 primaries
+float getLuma(float r, float g, float b) {
+    constexpr auto rec709_red_primary = 0.2126f;
+    constexpr auto rec709_green_primary = 0.7152f;
+    constexpr auto rec709_blue_primary = 0.0722f;
+    return rec709_red_primary * r + rec709_green_primary * g + rec709_blue_primary * b;
+}
+
+float sampleArea(const uint32_t* data, int32_t stride, const Rect& area) {
+    std::array<int32_t, 256> brightnessBuckets = {};
+    const int32_t majoritySampleNum = area.getWidth() * area.getHeight() / 2;
+
+    for (int32_t row = area.top; row < area.bottom; ++row) {
+        const uint32_t* rowBase = data + row * stride;
+        for (int32_t column = area.left; column < area.right; ++column) {
+            uint32_t pixel = rowBase[column];
+            const float r = (pixel & 0xFF) / 255.0f;
+            const float g = ((pixel >> 8) & 0xFF) / 255.0f;
+            const float b = ((pixel >> 16) & 0xFF) / 255.0f;
+            const uint8_t luma = std::round(getLuma(r, g, b) * 255.0f);
+            ++brightnessBuckets[luma];
+            if (brightnessBuckets[luma] > majoritySampleNum) return luma / 255.0f;
+        }
+    }
+
+    int32_t accumulated = 0;
+    size_t bucket = 0;
+    while (bucket++ < brightnessBuckets.size()) {
+        accumulated += brightnessBuckets[bucket];
+        if (accumulated > majoritySampleNum) break;
+    }
+
+    return bucket / 255.0f;
+}
+} // anonymous namespace
+
+std::vector<float> sampleBuffer(const sp<GraphicBuffer>& buffer, const Point& leftTop,
+                                const std::vector<RegionSamplingThread::Descriptor>& descriptors) {
+    void* data_raw = nullptr;
+    buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, &data_raw);
+    std::shared_ptr<uint32_t> data(reinterpret_cast<uint32_t*>(data_raw),
+                                   [&buffer](auto) { buffer->unlock(); });
+    if (!data) return {};
+
+    const int32_t stride = buffer->getStride();
+    std::vector<float> lumas(descriptors.size());
+    std::transform(descriptors.begin(), descriptors.end(), lumas.begin(),
+                   [&](auto const& descriptor) {
+                       return sampleArea(data.get(), stride, descriptor.area - leftTop);
+                   });
+    return lumas;
+}
+
+void RegionSamplingThread::captureSample() {
+    ATRACE_CALL();
+
+    if (mDescriptors.empty()) {
+        return;
+    }
+
+    std::vector<RegionSamplingThread::Descriptor> descriptors;
+    Region sampleRegion;
+    for (const auto& [listener, descriptor] : mDescriptors) {
+        sampleRegion.orSelf(descriptor.area);
+        descriptors.emplace_back(descriptor);
+    }
+
+    Rect sampledArea = sampleRegion.bounds();
+
+    sp<const DisplayDevice> device = mFlinger.getDefaultDisplayDevice();
+    DisplayRenderArea renderArea(device, sampledArea, sampledArea.getWidth(),
+                                 sampledArea.getHeight(), ui::Dataspace::V0_SRGB,
+                                 ui::Transform::ROT_0);
+
+    std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
+
+    auto traverseLayers = [&](const LayerVector::Visitor& visitor) {
+        bool stopLayerFound = false;
+        auto filterVisitor = [&](Layer* layer) {
+            // We don't want to capture any layers beyond the stop layer
+            if (stopLayerFound) return;
+
+            // Likewise if we just found a stop layer, set the flag and abort
+            for (const auto& [area, stopLayer, listener] : descriptors) {
+                if (layer == stopLayer.promote().get()) {
+                    stopLayerFound = true;
+                    return;
+                }
+            }
+
+            // Compute the layer's position on the screen
+            Rect bounds = Rect(layer->getBounds());
+            ui::Transform transform = layer->getTransform();
+            constexpr bool roundOutwards = true;
+            Rect transformed = transform.transform(bounds, roundOutwards);
+
+            // If this layer doesn't intersect with the larger sampledArea, skip capturing it
+            Rect ignore;
+            if (!transformed.intersect(sampledArea, &ignore)) return;
+
+            // If the layer doesn't intersect a sampling area, skip capturing it
+            bool intersectsAnyArea = false;
+            for (const auto& [area, stopLayer, listener] : descriptors) {
+                if (transformed.intersect(area, &ignore)) {
+                    intersectsAnyArea = true;
+                    listeners.insert(listener);
+                }
+            }
+            if (!intersectsAnyArea) return;
+
+            ALOGV("Traversing [%s] [%d, %d, %d, %d]", layer->getName().string(), bounds.left,
+                  bounds.top, bounds.right, bounds.bottom);
+            visitor(layer);
+        };
+        mFlinger.traverseLayersInDisplay(device, filterVisitor);
+    };
+
+    const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(sampledArea.getWidth(), sampledArea.getHeight(),
+                              PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+
+    // When calling into SF, we post a message into the SF message queue (so the
+    // screen capture runs on the main thread). This message blocks until the
+    // screenshot is actually captured, but before the capture occurs, the main
+    // thread may perform a normal refresh cycle. At the end of this cycle, it
+    // can request another sample (because layers changed), which triggers a
+    // call into sampleNow. When sampleNow attempts to grab the mutex, we can
+    // deadlock.
+    //
+    // To avoid this, we drop the mutex while we call into SF.
+    mMutex.unlock();
+    mFlinger.captureScreenCore(renderArea, traverseLayers, buffer, false);
+    mMutex.lock();
+
+    std::vector<Descriptor> activeDescriptors;
+    for (const auto& descriptor : descriptors) {
+        if (listeners.count(descriptor.listener) != 0) {
+            activeDescriptors.emplace_back(descriptor);
+        }
+    }
+
+    ALOGV("Sampling %zu descriptors", activeDescriptors.size());
+    std::vector<float> lumas = sampleBuffer(buffer, sampledArea.leftTop(), activeDescriptors);
+
+    if (lumas.size() != activeDescriptors.size()) {
+        return;
+    }
+
+    for (size_t d = 0; d < activeDescriptors.size(); ++d) {
+        activeDescriptors[d].listener->onSampleCollected(lumas[d]);
+    }
+}
+
+void RegionSamplingThread::threadMain() {
+    std::lock_guard lock(mMutex);
+    while (mRunning) {
+        if (mSampleRequested) {
+            mSampleRequested = false;
+            captureSample();
+        }
+        mCondition.wait(mMutex,
+                        [this]() REQUIRES(mMutex) { return mSampleRequested || !mRunning; });
+    }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
new file mode 100644
index 0000000..bf59007
--- /dev/null
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -0,0 +1,77 @@
+/*
+ * 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 <condition_variable>
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+
+#include <android-base/thread_annotations.h>
+#include <binder/IBinder.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class GraphicBuffer;
+class IRegionSamplingListener;
+class Layer;
+class SurfaceFlinger;
+
+class RegionSamplingThread : public IBinder::DeathRecipient {
+public:
+    explicit RegionSamplingThread(SurfaceFlinger& flinger);
+    ~RegionSamplingThread();
+
+    void addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+                     const sp<IRegionSamplingListener>& listener);
+    void removeListener(const sp<IRegionSamplingListener>& listener);
+    void sampleNow();
+
+    struct Descriptor {
+        Rect area = Rect::EMPTY_RECT;
+        wp<Layer> stopLayer;
+        sp<IRegionSamplingListener> listener;
+    };
+
+    struct WpHash {
+        size_t operator()(const wp<IBinder>& p) const {
+            return std::hash<IBinder*>()(p.unsafe_get());
+        }
+    };
+
+private:
+    void binderDied(const wp<IBinder>& who) override;
+
+    void captureSample() REQUIRES(mMutex);
+    void threadMain();
+
+    SurfaceFlinger& mFlinger;
+
+    std::mutex mThreadMutex;
+    std::thread mThread GUARDED_BY(mThreadMutex);
+
+    std::mutex mMutex;
+    std::condition_variable_any mCondition;
+    bool mRunning GUARDED_BY(mMutex) = true;
+    bool mSampleRequested GUARDED_BY(mMutex) = false;
+
+    std::unordered_map<wp<IBinder>, Descriptor, WpHash> mDescriptors GUARDED_BY(mMutex);
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 9bad6de..edc6442 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -7,6 +7,8 @@
 
 namespace android {
 
+class DisplayDevice;
+
 // RenderArea describes a rectangular area that layers can be rendered to.
 //
 // There is a logical render area and a physical render area.  When a layer is
@@ -76,6 +78,8 @@
     // covered by any rendered layer should be filled with this color.
     CaptureFill getCaptureFill() const { return mCaptureFill; };
 
+    virtual const sp<const DisplayDevice> getDisplayDevice() const = 0;
+
 private:
     const uint32_t mReqWidth;
     const uint32_t mReqHeight;
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 697d634..d848c97 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -85,7 +85,19 @@
     }
 }
 
+void DispSyncSource::pauseVsyncCallback(bool pause) {
+    std::lock_guard lock(mVsyncMutex);
+    mCallbackPaused = pause;
+}
+
 void DispSyncSource::onDispSyncEvent(nsecs_t when) {
+    {
+        std::lock_guard lock(mVsyncMutex);
+        if (mCallbackPaused) {
+            return;
+        }
+    }
+
     VSyncSource::Callback* callback;
     {
         std::lock_guard lock(mCallbackMutex);
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 0fd84a2..5e3d181 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -33,6 +33,7 @@
     void setVSyncEnabled(bool enable) override;
     void setCallback(VSyncSource::Callback* callback) override;
     void setPhaseOffset(nsecs_t phaseOffset) override;
+    void pauseVsyncCallback(bool pause) override;
 
 private:
     // The following method is the implementation of the DispSync::Callback.
@@ -53,6 +54,7 @@
     std::mutex mVsyncMutex;
     nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex);
     bool mEnabled GUARDED_BY(mVsyncMutex) = false;
+    bool mCallbackPaused GUARDED_BY(mVsyncMutex) = false;
 };
 
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 52abe9c..4b500f1 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -69,24 +69,28 @@
 std::string toString(const DisplayEventReceiver::Event& event) {
     switch (event.header.type) {
         case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
-            return StringPrintf("Hotplug{displayId=%u, %s}", event.header.id,
+            return StringPrintf("Hotplug{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", %s}",
+                                event.header.displayId,
                                 event.hotplug.connected ? "connected" : "disconnected");
         case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
-            return StringPrintf("VSync{displayId=%u, count=%u}", event.header.id,
-                                event.vsync.count);
+            return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+                                ", count=%u}",
+                                event.header.displayId, event.vsync.count);
         default:
             return "Event{}";
     }
 }
 
-DisplayEventReceiver::Event makeHotplug(uint32_t displayId, nsecs_t timestamp, bool connected) {
+DisplayEventReceiver::Event makeHotplug(PhysicalDisplayId displayId, nsecs_t timestamp,
+                                        bool connected) {
     DisplayEventReceiver::Event event;
     event.header = {DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, displayId, timestamp};
     event.hotplug.connected = connected;
     return event;
 }
 
-DisplayEventReceiver::Event makeVSync(uint32_t displayId, nsecs_t timestamp, uint32_t count) {
+DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp,
+                                      uint32_t count) {
     DisplayEventReceiver::Event event;
     event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
     event.vsync.count = count;
@@ -96,8 +100,10 @@
 } // namespace
 
 EventThreadConnection::EventThreadConnection(EventThread* eventThread,
-                                             ResyncCallback resyncCallback)
+                                             ResyncCallback resyncCallback,
+                                             ResetIdleTimerCallback resetIdleTimerCallback)
       : resyncCallback(std::move(resyncCallback)),
+        resetIdleTimerCallback(std::move(resetIdleTimerCallback)),
         mEventThread(eventThread),
         mChannel(gui::BitTube::DefaultSize) {}
 
@@ -143,22 +149,18 @@
 namespace impl {
 
 EventThread::EventThread(std::unique_ptr<VSyncSource> src,
-                         const InterceptVSyncsCallback& interceptVSyncsCallback,
-                         const ResetIdleTimerCallback& resetIdleTimerCallback,
-                         const char* threadName)
-      : EventThread(nullptr, std::move(src), interceptVSyncsCallback, threadName) {
-    mResetIdleTimer = resetIdleTimerCallback;
-}
+                         InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
+      : EventThread(nullptr, std::move(src), std::move(interceptVSyncsCallback), threadName) {}
 
 EventThread::EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
                          const char* threadName)
-      : EventThread(src, nullptr, interceptVSyncsCallback, threadName) {}
+      : EventThread(src, nullptr, std::move(interceptVSyncsCallback), threadName) {}
 
 EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
                          InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
       : mVSyncSource(src),
         mVSyncSourceUnique(std::move(uniqueSrc)),
-        mInterceptVSyncsCallback(interceptVSyncsCallback),
+        mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
         mThreadName(threadName) {
     if (src == nullptr) {
         mVSyncSource = mVSyncSourceUnique.get();
@@ -201,8 +203,16 @@
     mVSyncSource->setPhaseOffset(phaseOffset);
 }
 
-sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const {
-    return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback));
+void EventThread::pauseVsyncCallback(bool pause) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    ATRACE_INT("vsyncPaused", pause);
+    mVSyncSource->pauseVsyncCallback(pause);
+}
+
+sp<EventThreadConnection> EventThread::createEventConnection(
+        ResyncCallback resyncCallback, ResetIdleTimerCallback resetIdleTimerCallback) const {
+    return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback),
+                                     std::move(resetIdleTimerCallback));
 }
 
 status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
@@ -245,9 +255,9 @@
 }
 
 void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection, bool reset) {
-    if (mResetIdleTimer && reset) {
+    if (connection->resetIdleTimerCallback && reset) {
         ATRACE_NAME("resetIdleTimer");
-        mResetIdleTimer();
+        connection->resetIdleTimerCallback();
     }
 
     if (connection->resyncCallback) {
@@ -290,10 +300,9 @@
     mCondition.notify_all();
 }
 
-void EventThread::onHotplugReceived(DisplayType displayType, bool connected) {
+void EventThread::onHotplugReceived(PhysicalDisplayId displayId, bool connected) {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    const uint32_t displayId = displayType == DisplayType::Primary ? 0 : 1;
     mPendingEvents.push_back(makeHotplug(displayId, systemTime(), connected));
     mCondition.notify_all();
 }
@@ -312,9 +321,9 @@
             switch (event->header.type) {
                 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
                     if (event->hotplug.connected && !mVSyncState) {
-                        mVSyncState.emplace(event->header.id);
+                        mVSyncState.emplace(event->header.displayId);
                     } else if (!event->hotplug.connected && mVSyncState &&
-                               mVSyncState->displayId == event->header.id) {
+                               mVSyncState->displayId == event->header.displayId) {
                         mVSyncState.reset();
                     }
                     break;
@@ -440,8 +449,9 @@
 
     StringAppendF(&result, "%s: state=%s VSyncState=", mThreadName, toCString(mState));
     if (mVSyncState) {
-        StringAppendF(&result, "{displayId=%u, count=%u%s}\n", mVSyncState->displayId,
-                      mVSyncState->count, mVSyncState->synthetic ? ", synthetic" : "");
+        StringAppendF(&result, "{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%u%s}\n",
+                      mVSyncState->displayId, mVSyncState->count,
+                      mVSyncState->synthetic ? ", synthetic" : "");
     } else {
         StringAppendF(&result, "none\n");
     }
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 89b799e..3411438 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -45,6 +45,7 @@
 // ---------------------------------------------------------------------------
 
 using ResyncCallback = std::function<void()>;
+using ResetIdleTimerCallback = std::function<void()>;
 
 enum class VSyncRequest {
     None = -1,
@@ -65,11 +66,14 @@
     virtual void setVSyncEnabled(bool enable) = 0;
     virtual void setCallback(Callback* callback) = 0;
     virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
+
+    // pause/resume vsync callback generation
+    virtual void pauseVsyncCallback(bool pause) = 0;
 };
 
 class EventThreadConnection : public BnDisplayEventConnection {
 public:
-    EventThreadConnection(EventThread* eventThread, ResyncCallback resyncCallback);
+    EventThreadConnection(EventThread*, ResyncCallback, ResetIdleTimerCallback);
     virtual ~EventThreadConnection();
 
     virtual status_t postEvent(const DisplayEventReceiver::Event& event);
@@ -83,6 +87,7 @@
 
     // Called in response to requestNextVsync.
     const ResyncCallback resyncCallback;
+    const ResetIdleTimerCallback resetIdleTimerCallback;
 
     VSyncRequest vsyncRequest = VSyncRequest::None;
 
@@ -94,13 +99,10 @@
 
 class EventThread {
 public:
-    // TODO: Remove once stable display IDs are plumbed through SF/WM interface.
-    enum class DisplayType { Primary, External };
-
     virtual ~EventThread();
 
-    virtual sp<EventThreadConnection> createEventConnection(
-            ResyncCallback resyncCallback) const = 0;
+    virtual sp<EventThreadConnection> createEventConnection(ResyncCallback,
+                                                            ResetIdleTimerCallback) const = 0;
 
     // called before the screen is turned off from main thread
     virtual void onScreenReleased() = 0;
@@ -108,8 +110,7 @@
     // called after the screen is turned on from main thread
     virtual void onScreenAcquired() = 0;
 
-    // called when receiving a hotplug event
-    virtual void onHotplugReceived(DisplayType displayType, bool connected) = 0;
+    virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
 
     virtual void dump(std::string& result) const = 0;
 
@@ -121,6 +122,8 @@
     // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
     virtual void requestNextVsync(const sp<EventThreadConnection>& connection,
                                   bool resetIdleTimer) = 0;
+
+    virtual void pauseVsyncCallback(bool pause) = 0;
 };
 
 namespace impl {
@@ -128,17 +131,14 @@
 class EventThread : public android::EventThread, private VSyncSource::Callback {
 public:
     using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
-    using ResetIdleTimerCallback = std::function<void()>;
 
     // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
-    EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
-                const char* threadName);
-    EventThread(std::unique_ptr<VSyncSource> src,
-                const InterceptVSyncsCallback& interceptVSyncsCallback,
-                const ResetIdleTimerCallback& resetIdleTimerCallback, const char* threadName);
+    EventThread(VSyncSource*, InterceptVSyncsCallback, const char* threadName);
+    EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback, const char* threadName);
     ~EventThread();
 
-    sp<EventThreadConnection> createEventConnection(ResyncCallback resyncCallback) const override;
+    sp<EventThreadConnection> createEventConnection(ResyncCallback,
+                                                    ResetIdleTimerCallback) const override;
 
     status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
     void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
@@ -151,13 +151,14 @@
     // called after the screen is turned on from main thread
     void onScreenAcquired() override;
 
-    // called when receiving a hotplug event
-    void onHotplugReceived(DisplayType displayType, bool connected) override;
+    void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
 
     void dump(std::string& result) const override;
 
     void setPhaseOffset(nsecs_t phaseOffset) override;
 
+    void pauseVsyncCallback(bool pause) override;
+
 private:
     friend EventThreadTest;
 
@@ -199,9 +200,9 @@
 
     // VSYNC state of connected display.
     struct VSyncState {
-        explicit VSyncState(uint32_t displayId) : displayId(displayId) {}
+        explicit VSyncState(PhysicalDisplayId displayId) : displayId(displayId) {}
 
-        const uint32_t displayId;
+        const PhysicalDisplayId displayId;
 
         // Number of VSYNC events since display was connected.
         uint32_t count = 0;
@@ -225,9 +226,6 @@
     State mState GUARDED_BY(mMutex) = State::Idle;
 
     static const char* toCString(State);
-
-    // Callback that resets the idle timer when the next vsync is received.
-    ResetIdleTimerCallback mResetIdleTimer;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Scheduler/IdleTimer.cpp b/services/surfaceflinger/Scheduler/IdleTimer.cpp
index 5a76dbc..b28b1aa 100644
--- a/services/surfaceflinger/Scheduler/IdleTimer.cpp
+++ b/services/surfaceflinger/Scheduler/IdleTimer.cpp
@@ -22,8 +22,9 @@
 namespace android {
 namespace scheduler {
 
-IdleTimer::IdleTimer(const Interval& interval, const TimeoutCallback& timeoutCallback)
-      : mInterval(interval), mTimeoutCallback(timeoutCallback) {}
+IdleTimer::IdleTimer(const Interval& interval, const ResetCallback& resetCallback,
+                     const TimeoutCallback& timeoutCallback)
+      : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {}
 
 IdleTimer::~IdleTimer() {
     stop();
@@ -49,23 +50,52 @@
 }
 
 void IdleTimer::loop() {
-    std::lock_guard<std::mutex> lock(mMutex);
-    while (mState != TimerState::STOPPED) {
-        if (mState == TimerState::IDLE) {
-            mCondition.wait(mMutex);
-        } else if (mState == TimerState::RESET) {
-            mState = TimerState::WAITING;
-            if (mCondition.wait_for(mMutex, mInterval) == std::cv_status::timeout) {
-                if (mTimeoutCallback) {
-                    mTimeoutCallback();
-                }
+    while (true) {
+        bool triggerReset = false;
+        bool triggerTimeout = false;
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            if (mState == TimerState::STOPPED) {
+                break;
             }
-            if (mState == TimerState::WAITING) {
-                mState = TimerState::IDLE;
+
+            if (mState == TimerState::IDLE) {
+                mCondition.wait(mMutex);
+                continue;
+            }
+
+            if (mState == TimerState::RESET) {
+                triggerReset = true;
             }
         }
+        if (triggerReset && mResetCallback) {
+            mResetCallback();
+        }
+
+        { // lock the mutex again. someone might have called stop meanwhile
+            std::lock_guard<std::mutex> lock(mMutex);
+            if (mState == TimerState::STOPPED) {
+                break;
+            }
+
+            auto triggerTime = std::chrono::steady_clock::now() + mInterval;
+            mState = TimerState::WAITING;
+            while (mState == TimerState::WAITING) {
+                constexpr auto zero = std::chrono::steady_clock::duration::zero();
+                auto waitTime = triggerTime - std::chrono::steady_clock::now();
+                if (waitTime > zero) mCondition.wait_for(mMutex, waitTime);
+                if (mState == TimerState::WAITING &&
+                    (triggerTime - std::chrono::steady_clock::now()) <= zero) {
+                    triggerTimeout = true;
+                    mState = TimerState::IDLE;
+                }
+            }
+        }
+        if (triggerTimeout && mTimeoutCallback) {
+            mTimeoutCallback();
+        }
     }
-}
+} // namespace scheduler
 
 void IdleTimer::reset() {
     {
diff --git a/services/surfaceflinger/Scheduler/IdleTimer.h b/services/surfaceflinger/Scheduler/IdleTimer.h
index aee3fa3..19f1267 100644
--- a/services/surfaceflinger/Scheduler/IdleTimer.h
+++ b/services/surfaceflinger/Scheduler/IdleTimer.h
@@ -32,9 +32,11 @@
 class IdleTimer {
 public:
     using Interval = std::chrono::milliseconds;
+    using ResetCallback = std::function<void()>;
     using TimeoutCallback = std::function<void()>;
 
-    IdleTimer(const Interval& interval, const TimeoutCallback& timeoutCallback);
+    IdleTimer(const Interval& interval, const ResetCallback& resetCallback,
+              const TimeoutCallback& timeoutCallback);
     ~IdleTimer();
 
     void start();
@@ -62,6 +64,9 @@
     // Interval after which timer expires.
     const Interval mInterval;
 
+    // Callback that happens when timer resets.
+    const ResetCallback mResetCallback;
+
     // Callback that happens when timer expires.
     const TimeoutCallback mTimeoutCallback;
 };
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
index a0e1447..90609af 100644
--- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h
+++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
@@ -44,6 +44,7 @@
 
     void setVSyncEnabled(bool) override {}
     void setPhaseOffset(nsecs_t) override {}
+    void pauseVsyncCallback(bool) {}
 
 private:
     std::mutex mCallbackMutex;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 75a410b..1f18ead 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -96,7 +96,8 @@
     }
 
     mEventThread = eventThread;
-    mEvents = eventThread->createEventConnection(std::move(resyncCallback));
+    mEvents =
+            eventThread->createEventConnection(std::move(resyncCallback), ResetIdleTimerCallback());
     mEvents->stealReceiveChannel(&mEventTube);
     mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
                    this);
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index a0a4455..ab1f460 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -59,10 +59,10 @@
     const int highFpsEarlyGlAppOffsetNs = atoi(value);
 
     // TODO(b/122905996): Define these in device.mk.
-    property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "1000000");
+    property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "2000000");
     const int highFpsLateAppOffsetNs = atoi(value);
 
-    property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "8000000");
+    property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000");
     const int highFpsLateSfOffsetNs = atoi(value);
 
     mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs
@@ -83,7 +83,7 @@
                                                                       : highFpsLateAppOffsetNs,
                                        highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
                                                                        : highFpsLateSfOffsetNs};
-    mHighRefreshRateOffsets.late = {highFpsLateAppOffsetNs, highFpsLateSfOffsetNs};
+    mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs};
 }
 
 PhaseOffsets::Offsets PhaseOffsets::getCurrentOffsets() const {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 00820f1..4f846db 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -29,7 +29,6 @@
 #include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
 #include <cutils/properties.h>
-#include <gui/ISurfaceComposer.h>
 #include <ui/DisplayStatInfo.h>
 #include <utils/Timers.h>
 #include <utils/Trace.h>
@@ -70,18 +69,22 @@
     mEventControlThread = std::make_unique<impl::EventControlThread>(function);
 
     char value[PROPERTY_VALUE_MAX];
-    property_get("debug.sf.set_idle_timer_ms", value, "30");
+    property_get("debug.sf.set_idle_timer_ms", value, "0");
     mSetIdleTimerMs = atoi(value);
 
     if (mSetIdleTimerMs > 0) {
         mIdleTimer =
                 std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(mSetIdleTimerMs),
+                                                       [this] { resetTimerCallback(); },
                                                        [this] { expiredTimerCallback(); });
         mIdleTimer->start();
     }
 }
 
-Scheduler::~Scheduler() = default;
+Scheduler::~Scheduler() {
+    // Ensure the IdleTimer thread is joined before we start destroying state.
+    mIdleTimer.reset();
+}
 
 sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
         const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
@@ -92,12 +95,13 @@
     std::unique_ptr<EventThread> eventThread =
             makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
                             std::move(interceptCallback));
-    auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
-                                                   eventThread->createEventConnection(
-                                                           std::move(resyncCallback)),
-                                                   std::move(eventThread));
 
-    mConnections.insert(std::make_pair(id, std::move(connection)));
+    auto eventThreadConnection =
+            createConnectionInternal(eventThread.get(), std::move(resyncCallback));
+    mConnections.emplace(id,
+                         std::make_unique<Connection>(new ConnectionHandle(id),
+                                                      eventThreadConnection,
+                                                      std::move(eventThread)));
     return mConnections[id]->handle;
 }
 
@@ -107,14 +111,20 @@
     std::unique_ptr<VSyncSource> eventThreadSource =
             std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
     return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
-                                               std::move(interceptCallback),
-                                               [this] { resetIdleTimer(); }, connectionName);
+                                               std::move(interceptCallback), connectionName);
+}
+
+sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread,
+                                                              ResyncCallback&& resyncCallback) {
+    return eventThread->createEventConnection(std::move(resyncCallback),
+                                              [this] { resetIdleTimer(); });
 }
 
 sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
         const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) {
     RETURN_VALUE_IF_INVALID(nullptr);
-    return mConnections[handle->id]->thread->createEventConnection(std::move(resyncCallback));
+    return createConnectionInternal(mConnections[handle->id]->thread.get(),
+                                    std::move(resyncCallback));
 }
 
 EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -128,9 +138,9 @@
 }
 
 void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle,
-                                EventThread::DisplayType displayType, bool connected) {
+                                PhysicalDisplayId displayId, bool connected) {
     RETURN_IF_INVALID();
-    mConnections[handle->id]->thread->onHotplugReceived(displayType, connected);
+    mConnections[handle->id]->thread->onHotplugReceived(displayId, connected);
 }
 
 void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -153,6 +163,12 @@
     mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
 }
 
+void Scheduler::pauseVsyncCallback(const android::sp<android::Scheduler::ConnectionHandle>& handle,
+                                   bool pause) {
+    RETURN_IF_INVALID();
+    mConnections[handle->id]->thread->pauseVsyncCallback(pause);
+}
+
 void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
     stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
     stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
@@ -179,10 +195,59 @@
     }
 }
 
+void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
+    {
+        std::lock_guard<std::mutex> lock(mHWVsyncLock);
+        if (makeAvailable) {
+            mHWVsyncAvailable = makeAvailable;
+        } else if (!mHWVsyncAvailable) {
+            // Hardware vsync is not currently available, so abort the resync
+            // attempt for now
+            return;
+        }
+    }
+
+    if (period <= 0) {
+        return;
+    }
+
+    setVsyncPeriod(period);
+}
+
+ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
+    std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
+    return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
+        if (const auto vsync = ptr.lock()) {
+            vsync->resync(getVsyncPeriod);
+        }
+    };
+}
+
+void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
+    static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
+
+    const nsecs_t now = systemTime();
+    const nsecs_t last = lastResyncTime.exchange(now);
+
+    if (now - last > kIgnoreDelay) {
+        scheduler.resyncToHardwareVsync(false, getVsyncPeriod());
+    }
+}
+
+void Scheduler::setRefreshSkipCount(int count) {
+    mPrimaryDispSync->setRefreshSkipCount(count);
+}
+
 void Scheduler::setVsyncPeriod(const nsecs_t period) {
+    std::lock_guard<std::mutex> lock(mHWVsyncLock);
     mPrimaryDispSync->reset();
     mPrimaryDispSync->setPeriod(period);
-    enableHardwareVsync();
+
+    if (!mPrimaryHWVsyncEnabled) {
+        mPrimaryDispSync->beginResync();
+        mEventControlThread->setVsyncEnabled(true);
+        mPrimaryHWVsyncEnabled = true;
+    }
 }
 
 void Scheduler::addResyncSample(const nsecs_t timestamp) {
@@ -213,9 +278,12 @@
     mPrimaryDispSync->setIgnorePresentFences(ignore);
 }
 
-void Scheduler::makeHWSyncAvailable(bool makeAvailable) {
-    std::lock_guard<std::mutex> lock(mHWVsyncLock);
-    mHWVsyncAvailable = makeAvailable;
+nsecs_t Scheduler::expectedPresentTime() {
+    return mPrimaryDispSync->expectedPresentTime();
+}
+
+void Scheduler::dumpPrimaryDispSync(std::string& result) const {
+    mPrimaryDispSync->dump(result);
 }
 
 void Scheduler::addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
@@ -231,6 +299,7 @@
 }
 
 void Scheduler::incrementFrameCounter() {
+    std::lock_guard<std::mutex> lock(mLayerHistoryLock);
     mLayerHistory.incrementCounter();
 }
 
@@ -255,25 +324,28 @@
 
 void Scheduler::determineLayerTimestampStats(const std::string layerName,
                                              const nsecs_t framePresentTime) {
-    mLayerHistory.insert(layerName, framePresentTime);
     std::vector<int64_t> differencesMs;
-
-    // Traverse through the layer history, and determine the differences in present times.
-    nsecs_t newestPresentTime = framePresentTime;
     std::string differencesText = "";
-    for (int i = 1; i < mLayerHistory.getSize(); i++) {
-        std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i);
-        for (auto layer : layers) {
-            if (layer.first != layerName) {
-                continue;
+    {
+        std::lock_guard<std::mutex> lock(mLayerHistoryLock);
+        mLayerHistory.insert(layerName, framePresentTime);
+
+        // Traverse through the layer history, and determine the differences in present times.
+        nsecs_t newestPresentTime = framePresentTime;
+        for (int i = 1; i < mLayerHistory.getSize(); i++) {
+            std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i);
+            for (auto layer : layers) {
+                if (layer.first != layerName) {
+                    continue;
+                }
+                int64_t differenceMs = (newestPresentTime - layer.second) / 1000000;
+                // Dismiss noise.
+                if (differenceMs > 10 && differenceMs < 60) {
+                    differencesMs.push_back(differenceMs);
+                }
+                IF_ALOGV() { differencesText += (std::to_string(differenceMs) + " "); }
+                newestPresentTime = layer.second;
             }
-            int64_t differenceMs = (newestPresentTime - layer.second) / 1000000;
-            // Dismiss noise.
-            if (differenceMs > 10 && differenceMs < 60) {
-                differencesMs.push_back(differenceMs);
-            }
-            IF_ALOGV() { differencesText += (std::to_string(differenceMs) + " "); }
-            newestPresentTime = layer.second;
         }
     }
     ALOGV("Layer %s timestamp intervals: %s", layerName.c_str(), differencesText.c_str());
@@ -332,12 +404,14 @@
 void Scheduler::resetIdleTimer() {
     if (mIdleTimer) {
         mIdleTimer->reset();
-        ATRACE_INT("ExpiredIdleTimer", 0);
     }
+}
 
+void Scheduler::resetTimerCallback() {
     std::lock_guard<std::mutex> lock(mCallbackLock);
     if (mResetTimerCallback) {
         mResetTimerCallback();
+        ATRACE_INT("ExpiredIdleTimer", 0);
     }
 }
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index b717605..c566922 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -19,8 +19,8 @@
 #include <cstdint>
 #include <memory>
 
-#include <gui/ISurfaceComposer.h>
 #include <ui/DisplayStatInfo.h>
+#include <ui/GraphicTypes.h>
 
 #include "DispSync.h"
 #include "EventControlThread.h"
@@ -37,6 +37,7 @@
 class Scheduler {
 public:
     using ExpiredIdleTimerCallback = std::function<void()>;
+    using GetVsyncPeriod = std::function<nsecs_t()>;
     using ResetIdleTimerCallback = std::function<void()>;
 
     // Enum to indicate whether to start the transaction early, or at vsync time.
@@ -67,17 +68,27 @@
         const std::unique_ptr<EventThread> thread;
     };
 
+    // Stores per-display state about VSYNC.
+    struct VsyncState {
+        explicit VsyncState(Scheduler& scheduler) : scheduler(scheduler) {}
+
+        void resync(const GetVsyncPeriod&);
+
+        Scheduler& scheduler;
+        std::atomic<nsecs_t> lastResyncTime = 0;
+    };
+
     explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function);
 
     virtual ~Scheduler();
 
     /** Creates an EventThread connection. */
-    sp<ConnectionHandle> createConnection(
-            const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
-            impl::EventThread::InterceptVSyncsCallback interceptCallback);
+    sp<ConnectionHandle> createConnection(const char* connectionName, int64_t phaseOffsetNs,
+                                          ResyncCallback,
+                                          impl::EventThread::InterceptVSyncsCallback);
 
     sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
-                                                             ResyncCallback resyncCallback);
+                                                             ResyncCallback);
 
     // Getter methods.
     EventThread* getEventThread(const sp<ConnectionHandle>& handle);
@@ -85,7 +96,7 @@
     sp<EventThreadConnection> getEventConnection(const sp<ConnectionHandle>& handle);
 
     // Should be called when receiving a hotplug event.
-    void hotplugReceived(const sp<ConnectionHandle>& handle, EventThread::DisplayType displayType,
+    void hotplugReceived(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
                          bool connected);
 
     // Should be called after the screen is turned on.
@@ -100,15 +111,21 @@
     // Offers ability to modify phase offset in the event thread.
     void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset);
 
+    // pause/resume vsync callback generation to avoid sending vsync callbacks during config switch
+    void pauseVsyncCallback(const sp<ConnectionHandle>& handle, bool pause);
+
     void getDisplayStatInfo(DisplayStatInfo* stats);
 
     void enableHardwareVsync();
     void disableHardwareVsync(bool makeUnavailable);
-    void setVsyncPeriod(const nsecs_t period);
+    void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
+    // Creates a callback for resyncing.
+    ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod);
+    void setRefreshSkipCount(int count);
     void addResyncSample(const nsecs_t timestamp);
     void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
     void setIgnorePresentFences(bool ignore);
-    void makeHWSyncAvailable(bool makeAvailable);
+    nsecs_t expectedPresentTime();
     // Adds the present time for given layer to the history of present times.
     void addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
                                      const std::string layerName);
@@ -121,12 +138,20 @@
     // Returns relevant information about Scheduler for dumpsys purposes.
     std::string doDump();
 
+    // calls DispSync::dump() on primary disp sync
+    void dumpPrimaryDispSync(std::string& result) const;
+
 protected:
     virtual std::unique_ptr<EventThread> makeEventThread(
             const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
             impl::EventThread::InterceptVSyncsCallback interceptCallback);
 
 private:
+    friend class TestableScheduler;
+
+    // Creates a connection on the given EventThread and forwards the given callbacks.
+    sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&);
+
     nsecs_t calculateAverage() const;
     void updateFrameSkipping(const int64_t skipCount);
     // Collects the statistical mean (average) and median between timestamp
@@ -137,12 +162,12 @@
     void determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime);
     // Function that resets the idle timer.
     void resetIdleTimer();
+    // Function that is called when the timer resets.
+    void resetTimerCallback();
     // Function that is called when the timer expires.
     void expiredTimerCallback();
-
-    // TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it
-    // should make request to Scheduler to compute next refresh.
-    friend class BufferQueueLayer;
+    // Sets vsync period.
+    void setVsyncPeriod(const nsecs_t period);
 
     // If fences from sync Framework are supported.
     const bool mHasSyncFramework;
@@ -160,6 +185,7 @@
     std::mutex mHWVsyncLock;
     bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock);
     bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock);
+    const std::shared_ptr<VsyncState> mPrimaryVsyncState{std::make_shared<VsyncState>(*this)};
 
     std::unique_ptr<DispSync> mPrimaryDispSync;
     std::unique_ptr<EventControlThread> mEventControlThread;
@@ -175,7 +201,10 @@
     std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{};
     size_t mCounter = 0;
 
-    LayerHistory mLayerHistory;
+    // DetermineLayerTimestampStats is called from BufferQueueLayer::onFrameAvailable which
+    // can run on any thread, and cause failure.
+    std::mutex mLayerHistoryLock;
+    LayerHistory mLayerHistory GUARDED_BY(mLayerHistoryLock);
 
     // Timer that records time between requests for next vsync. If the time is higher than a given
     // interval, a callback is fired. Set this variable to >0 to use this feature.
@@ -184,7 +213,7 @@
 
     std::mutex mCallbackLock;
     ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
-    ResetIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
+    ExpiredIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index d7ec733..dab2003 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -54,6 +54,15 @@
         mEarlyOffsets = early;
         mEarlyGlOffsets = earlyGl;
         mLateOffsets = late;
+
+        if (mSfConnectionHandle && late.sf != mOffsets.load().sf) {
+            mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf);
+        }
+
+        if (mAppConnectionHandle && late.app != mOffsets.load().app) {
+            mScheduler->setPhaseOffset(mAppConnectionHandle, late.app);
+        }
+
         mOffsets = late;
     }
 
@@ -124,7 +133,7 @@
             changed = true;
         }
         if (desired.app != current.app) {
-            if (mSfConnectionHandle != nullptr) {
+            if (mAppConnectionHandle != nullptr) {
                 mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
             } else {
                 mAppEventThread->setPhaseOffset(desired.app);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b5b0108..df558e5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-// #define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <sys/types.h>
@@ -43,7 +43,9 @@
 #include <compositionengine/Layer.h>
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/LayerCompositionState.h>
 #include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <dvr/vr_flinger.h>
 #include <gui/BufferQueue.h>
 #include <gui/GuiConfig.h>
@@ -120,6 +122,7 @@
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 using namespace android::sysprop;
+
 using base::StringAppendF;
 using ui::ColorMode;
 using ui::Dataspace;
@@ -127,6 +130,8 @@
 using ui::Hdr;
 using ui::RenderIntent;
 
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
 namespace {
 
 #pragma clang diagnostic push
@@ -211,6 +216,9 @@
 constexpr float kSrgbWhiteY = 1.0000f;
 constexpr float kSrgbWhiteZ = 1.0891f;
 
+constexpr float kDefaultRefreshRate = 60.f;
+constexpr float kPerformanceRefreshRate = 90.f;
+
 // ---------------------------------------------------------------------------
 int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
 bool SurfaceFlinger::useHwcForRgbToYuv;
@@ -284,14 +292,14 @@
         mLastTransactionTime(0),
         mForceFullDamage(false),
         mTimeStats(factory.createTimeStats()),
-        mPrimaryHWVsyncEnabled(false),
-        mHWVsyncAvailable(false),
         mRefreshStartTime(0),
         mHasPoweredOff(false),
         mNumLayers(0),
         mVrFlingerRequestsDisplay(false),
         mMainThreadId(std::this_thread::get_id()),
-        mCompositionEngine{getFactory().createCompositionEngine()} {}
+        mCompositionEngine{getFactory().createCompositionEngine()} {
+    mSetInputWindowsListener = new SetInputWindowsListener(this);
+}
 
 SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory)
       : SurfaceFlinger(factory, SkipInitialization) {
@@ -345,10 +353,6 @@
     }
     ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation);
 
-    mPrimaryDispSync =
-            getFactory().createDispSync("PrimaryDispSync", SurfaceFlinger::hasSyncFramework,
-                                        SurfaceFlinger::dispSyncPresentTimeOffset);
-
     auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
     if (surfaceFlingerConfigsServiceV1_2) {
         surfaceFlingerConfigsServiceV1_2->getDisplayNativePrimaries(
@@ -391,8 +395,14 @@
     auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
     mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
 
-    property_get("debug.sf.use_scheduler", value, "0");
-    mUseScheduler = atoi(value);
+    property_get("debug.sf.use_90Hz", value, "0");
+    mUse90Hz = atoi(value);
+
+    property_get("debug.sf.use_smart_90_for_video", value, "0");
+    mUseSmart90ForVideo = atoi(value);
+
+    property_get("debug.sf.luma_sampling", value, "1");
+    mLumaSampling = atoi(value);
 
     const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
     mVsyncModulator.setPhaseOffsets(early, gl, late);
@@ -492,21 +502,30 @@
     setTransactionFlags(eDisplayTransactionNeeded);
 }
 
-sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
-    std::optional<DisplayId> displayId;
+std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const {
+    Mutex::Autolock lock(mStateLock);
 
-    if (id == HWC_DISPLAY_PRIMARY) {
-        displayId = getInternalDisplayId();
-    } else if (id == HWC_DISPLAY_EXTERNAL) {
-        displayId = getExternalDisplayId();
+    const auto internalDisplayId = getInternalDisplayIdLocked();
+    if (!internalDisplayId) {
+        return {};
     }
 
-    if (!displayId) {
-        ALOGE("%s: Invalid display %d", __FUNCTION__, id);
-        return nullptr;
+    std::vector<PhysicalDisplayId> displayIds;
+    displayIds.reserve(mPhysicalDisplayTokens.size());
+    displayIds.push_back(internalDisplayId->value);
+
+    for (const auto& [id, token] : mPhysicalDisplayTokens) {
+        if (id != *internalDisplayId) {
+            displayIds.push_back(id.value);
+        }
     }
 
-    return getPhysicalDisplayToken(*displayId);
+    return displayIds;
+}
+
+sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
+    Mutex::Autolock lock(mStateLock);
+    return getPhysicalDisplayTokenLocked(DisplayId{displayId});
 }
 
 status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const {
@@ -565,9 +584,24 @@
     LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
                    ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
 
-    postMessageAsync(new LambdaMessage([this] {
+    postMessageAsync(new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS {
         readPersistentProperties();
         mBootStage = BootStage::FINISHED;
+
+        // TODO(b/122905403): Once the display policy is completely integrated, this flag should go
+        // away and it should be controlled by flipping the switch in setting. The switch in
+        // settings should only be available to P19 devices, if they are opted into 90Hz fishfood.
+        // The boot must be complete before we can set the active config.
+
+        if (mUse90Hz) {
+            mPhaseOffsets->setRefreshRateType(
+                    scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
+            setRefreshRateTo(RefreshRateType::PERFORMANCE);
+        } else {
+            mPhaseOffsets->setRefreshRateType(
+                    scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
+            setRefreshRateTo(RefreshRateType::DEFAULT);
+        }
     }));
 }
 
@@ -605,53 +639,24 @@
     ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset());
 
     Mutex::Autolock _l(mStateLock);
-
-    auto resyncCallback = makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
-
     // start the EventThread
-    if (mUseScheduler) {
-        mScheduler = getFactory().createScheduler([this](bool enabled) {
-            setVsyncEnabled(EventThread::DisplayType::Primary, enabled);
-        });
-        // TODO(b/113612090): Currently we assume that if scheduler is turned on, then the refresh
-        // rate is 90. Once b/122905403 is completed, this should be updated accordingly.
-        mPhaseOffsets->setRefreshRateType(
-                scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
+    mScheduler =
+            getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); });
+    auto resyncCallback =
+            mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
 
-        mAppConnectionHandle =
-                mScheduler->createConnection("appConnection", mPhaseOffsets->getCurrentAppOffset(),
-                                             resyncCallback,
-                                             impl::EventThread::InterceptVSyncsCallback());
-        mSfConnectionHandle =
-                mScheduler->createConnection("sfConnection", mPhaseOffsets->getCurrentSfOffset(),
-                                             resyncCallback, [this](nsecs_t timestamp) {
-                                                 mInterceptor->saveVSyncEvent(timestamp);
-                                             });
+    mAppConnectionHandle =
+            mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
+                                         resyncCallback,
+                                         impl::EventThread::InterceptVSyncsCallback());
+    mSfConnectionHandle = mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
+                                                       resyncCallback, [this](nsecs_t timestamp) {
+                                                           mInterceptor->saveVSyncEvent(timestamp);
+                                                       });
 
-        mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
-        mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
-                                               mSfConnectionHandle.get());
-    } else {
-        mEventThreadSource =
-                std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
-                                                 mPhaseOffsets->getCurrentAppOffset(), true, "app");
-        mEventThread =
-                std::make_unique<impl::EventThread>(mEventThreadSource.get(),
-                                                    impl::EventThread::InterceptVSyncsCallback(),
-                                                    "appEventThread");
-        mSfEventThreadSource =
-                std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
-                                                 mPhaseOffsets->getCurrentSfOffset(), true, "sf");
-
-        mSFEventThread =
-                std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
-                                                    [this](nsecs_t timestamp) {
-                                                        mInterceptor->saveVSyncEvent(timestamp);
-                                                    },
-                                                    "sfEventThread");
-        mEventQueue->setEventThread(mSFEventThread.get(), std::move(resyncCallback));
-        mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
-    }
+    mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
+    mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
+                                           mSfConnectionHandle.get());
 
     // Get a RenderEngine for the given display / config (can't fail)
     int32_t renderEngineFeature = 0;
@@ -700,9 +705,6 @@
         }
     }
 
-    mEventControlThread = getFactory().createEventControlThread(
-            [this](bool enabled) { setVsyncEnabled(EventThread::DisplayType::Primary, enabled); });
-
     // initialize our drawing state
     mDrawingState = mCurrentState;
 
@@ -721,26 +723,19 @@
         ALOGE("Run StartPropertySetThread failed!");
     }
 
-    if (mUseScheduler) {
-        mScheduler->setExpiredIdleTimerCallback([this]() {
-            mPhaseOffsets->setRefreshRateType(
-                    scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
-            const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
-            mVsyncModulator.setPhaseOffsets(early, gl, late);
-            setRefreshRateTo(60.f /* fps */);
+    if (mUse90Hz) {
+        mScheduler->setExpiredIdleTimerCallback([this] {
+            Mutex::Autolock lock(mStateLock);
+            setRefreshRateTo(RefreshRateType::DEFAULT);
         });
-        mScheduler->setResetIdleTimerCallback([this]() {
-            mPhaseOffsets->setRefreshRateType(
-                    scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
-            const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
-            mVsyncModulator.setPhaseOffsets(early, gl, late);
-            setRefreshRateTo(90.f /* fps */);
+        mScheduler->setResetIdleTimerCallback([this] {
+            Mutex::Autolock lock(mStateLock);
+            setRefreshRateTo(RefreshRateType::PERFORMANCE);
         });
-        mRefreshRateStats =
-                std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
-                                                                      *display->getId()),
-                                                              mTimeStats);
     }
+    mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
+                                                                              *display->getId()),
+                                                                      mTimeStats);
 
     ALOGV("Done initializing");
 }
@@ -757,6 +752,9 @@
 
     property_get("persist.sys.sf.native_mode", value, "0");
     mDisplayColorSetting = static_cast<DisplayColorSetting>(atoi(value));
+
+    property_get("persist.sys.sf.color_mode", value, "0");
+    mForceColorMode = static_cast<ColorMode>(atoi(value));
 }
 
 void SurfaceFlinger::startBootAnim() {
@@ -812,13 +810,13 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken,
-                                           Vector<DisplayInfo>* configs) {
+status_t SurfaceFlinger::getDisplayConfigsLocked(const sp<IBinder>& displayToken,
+                                                 Vector<DisplayInfo>* configs) {
     if (!displayToken || !configs) {
         return BAD_VALUE;
     }
 
-    const auto displayId = getPhysicalDisplayId(displayToken);
+    const auto displayId = getPhysicalDisplayIdLocked(displayToken);
     if (!displayId) {
         return NAME_NOT_FOUND;
     }
@@ -842,8 +840,6 @@
 
     configs->clear();
 
-    ConditionalLock _l(mStateLock,
-            std::this_thread::get_id() != mMainThreadId);
     for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) {
         DisplayInfo info = DisplayInfo();
 
@@ -856,7 +852,7 @@
         info.viewportW = info.w;
         info.viewportH = info.h;
 
-        if (displayId == getInternalDisplayId()) {
+        if (displayId == getInternalDisplayIdLocked()) {
             // The density of the device is provided by a build property
             float density = Density::getBuildDensity() / 160.0f;
             if (density == 0) {
@@ -912,7 +908,7 @@
         // All non-virtual displays are currently considered secure.
         info.secure = true;
 
-        if (displayId == getInternalDisplayId() &&
+        if (displayId == getInternalDisplayIdLocked() &&
             primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
             std::swap(info.w, info.h);
         }
@@ -928,12 +924,7 @@
         return BAD_VALUE;
     }
 
-    if (mUseScheduler) {
-        mScheduler->getDisplayStatInfo(stats);
-    } else {
-        stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
-        stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
-    }
+    mScheduler->getDisplayStatInfo(stats);
     return NO_ERROR;
 }
 
@@ -947,29 +938,19 @@
     return display->getActiveConfig();
 }
 
-status_t SurfaceFlinger::setActiveConfigAsync(const sp<IBinder>& displayToken, int mode) {
-    ATRACE_NAME("setActiveConfigAsync");
-    postMessageAsync(new LambdaMessage(
-            [=]() NO_THREAD_SAFETY_ANALYSIS { setActiveConfigInternal(displayToken, mode); }));
-    return NO_ERROR;
-}
+void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode) {
+    ATRACE_CALL();
 
-status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
-    ATRACE_NAME("setActiveConfigSync");
-    postMessageSync(new LambdaMessage(
-            [&]() NO_THREAD_SAFETY_ANALYSIS { setActiveConfigInternal(displayToken, mode); }));
-    return NO_ERROR;
-}
-
-void SurfaceFlinger::setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) {
     Vector<DisplayInfo> configs;
-    getDisplayConfigs(displayToken, &configs);
+    // Lock is acquired by setRefreshRateTo.
+    getDisplayConfigsLocked(displayToken, &configs);
     if (mode < 0 || mode >= static_cast<int>(configs.size())) {
         ALOGE("Attempt to set active config %d for display with %zu configs", mode, configs.size());
         return;
     }
 
-    const auto display = getDisplayDevice(displayToken);
+    // Lock is acquired by setRefreshRateTo.
+    const auto display = getDisplayDeviceLocked(displayToken);
     if (!display) {
         ALOGE("Attempt to set active config %d for invalid display token %p", mode,
               displayToken.get());
@@ -985,23 +966,101 @@
         return;
     }
 
-    int currentMode = display->getActiveConfig();
-    if (mode == currentMode) {
-        // Don't update config if we are already running in the desired mode.
-        return;
+    // Don't check against the current mode yet. Worst case we set the desired
+    // config twice.
+    std::lock_guard<std::mutex> lock(mActiveConfigLock);
+    mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken};
+
+    if (!mDesiredActiveConfigChanged) {
+        // This is the first time we set the desired
+        mScheduler->pauseVsyncCallback(mAppConnectionHandle, true);
+
+        // This will trigger HWC refresh without resetting the idle timer.
+        repaintEverythingForHWC();
     }
-    if (mUseScheduler) {
-        mRefreshRateStats->setConfigMode(mode);
+    mDesiredActiveConfigChanged = true;
+    ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+}
+
+status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
+    ATRACE_CALL();
+    postMessageSync(new LambdaMessage(
+            [&]() NO_THREAD_SAFETY_ANALYSIS { setDesiredActiveConfig(displayToken, mode); }));
+    return NO_ERROR;
+}
+
+void SurfaceFlinger::setActiveConfigInternal() {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mActiveConfigLock);
+    mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId);
+
+    const auto display = getDisplayDeviceLocked(mUpcomingActiveConfig.displayToken);
+    display->setActiveConfig(mUpcomingActiveConfig.configId);
+
+    mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+    ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
+}
+
+bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS {
+    ATRACE_CALL();
+    // we may be in the process of changing the active state
+    if (mWaitForNextInvalidate) {
+        mWaitForNextInvalidate = false;
+
+        repaintEverythingForHWC();
+        // We do not want to give another frame to HWC while we are transitioning.
+        return true;
     }
 
+    if (mCheckPendingFence) {
+        if (mPreviousPresentFence != Fence::NO_FENCE &&
+            (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled)) {
+            // fence has not signaled yet. wait for the next invalidate
+            repaintEverythingForHWC();
+            return true;
+        }
+
+        // We received the present fence from the HWC, so we assume it successfully updated
+        // the config, hence we update SF.
+        mCheckPendingFence = false;
+        setActiveConfigInternal();
+    }
+
+    // Store the local variable to release the lock.
+    ActiveConfigInfo desiredActiveConfig;
+    {
+        std::lock_guard<std::mutex> lock(mActiveConfigLock);
+        if (!mDesiredActiveConfigChanged) {
+            return false;
+        }
+        desiredActiveConfig = mDesiredActiveConfig;
+    }
+
+    const auto display = getDisplayDevice(desiredActiveConfig.displayToken);
+    if (!display || display->getActiveConfig() == desiredActiveConfig.configId) {
+        // display is not valid or we are already in the requested mode
+        // on both cases there is nothing left to do
+        std::lock_guard<std::mutex> lock(mActiveConfigLock);
+        mScheduler->pauseVsyncCallback(mAppConnectionHandle, false);
+        mDesiredActiveConfigChanged = false;
+        ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+        return false;
+    }
+
+    // Desired active config was set, it is different than the config currently in use. Notify HWC.
+    mUpcomingActiveConfig = desiredActiveConfig;
     const auto displayId = display->getId();
     LOG_ALWAYS_FATAL_IF(!displayId);
 
-    display->setActiveConfig(mode);
-    getHwComposer().setActiveConfig(*displayId, mode);
+    ATRACE_INT("ActiveConfigModeHWC", mUpcomingActiveConfig.configId);
+    getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId);
 
-    ATRACE_INT("ActiveConfigMode", mode);
-    resyncToHardwareVsync(true, getVsyncPeriod());
+    // we need to submit an empty frame to HWC to start the process
+    mWaitForNextInvalidate = true;
+    mCheckPendingFence = true;
+
+    return false;
 }
 
 status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
@@ -1010,15 +1069,15 @@
         return BAD_VALUE;
     }
 
-    const auto displayId = getPhysicalDisplayId(displayToken);
-    if (!displayId) {
-        return NAME_NOT_FOUND;
-    }
-
     std::vector<ColorMode> modes;
     {
-        ConditionalLock _l(mStateLock,
-                std::this_thread::get_id() != mMainThreadId);
+        ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+
+        const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+        if (!displayId) {
+            return NAME_NOT_FOUND;
+        }
+
         modes = getHwComposer().getColorModes(*displayId);
     }
     outColorModes->clear();
@@ -1181,7 +1240,8 @@
             return;
         }
 
-        auto resyncCallback = makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
+        auto resyncCallback =
+                mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
 
         // TODO(akrulec): Part of the Injector should be refactored, so that it
         // can be passed to Scheduler.
@@ -1197,7 +1257,8 @@
             mEventQueue->setEventThread(mInjectorEventThread.get(), std::move(resyncCallback));
         } else {
             ALOGV("VSync Injections disabled");
-            mEventQueue->setEventThread(mSFEventThread.get(), std::move(resyncCallback));
+            mEventQueue->setEventThread(mScheduler->getEventThread(mSfConnectionHandle),
+                                        std::move(resyncCallback));
         }
 
         mInjectVSyncs = enable;
@@ -1250,28 +1311,33 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::addRegionSamplingListener(const Rect& samplingArea,
+                                                   const sp<IBinder>& stopLayerHandle,
+                                                   const sp<IRegionSamplingListener>& listener) {
+    if (!listener) {
+        return BAD_VALUE;
+    }
+    mRegionSamplingThread->addListener(samplingArea, stopLayerHandle, listener);
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) {
+    mRegionSamplingThread->removeListener(listener);
+    return NO_ERROR;
+}
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
         ISurfaceComposer::VsyncSource vsyncSource) {
-    auto resyncCallback = makeResyncCallback([this] {
+    auto resyncCallback = mScheduler->makeResyncCallback([this] {
         Mutex::Autolock lock(mStateLock);
         return getVsyncPeriod();
     });
 
-    if (mUseScheduler) {
-        if (vsyncSource == eVsyncSourceSurfaceFlinger) {
-            return mScheduler->createDisplayEventConnection(mSfConnectionHandle, resyncCallback);
-        } else {
-            return mScheduler->createDisplayEventConnection(mAppConnectionHandle, resyncCallback);
-        }
-    } else {
-        if (vsyncSource == eVsyncSourceSurfaceFlinger) {
-            return mSFEventThread->createEventConnection(resyncCallback);
-        } else {
-            return mEventThread->createEventConnection(resyncCallback);
-        }
-    }
+    const auto& handle =
+            vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;
+
+    return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback));
 }
 
 // ----------------------------------------------------------------------------
@@ -1314,7 +1380,7 @@
 }
 
 nsecs_t SurfaceFlinger::getVsyncPeriod() const {
-    const auto displayId = getInternalDisplayId();
+    const auto displayId = getInternalDisplayIdLocked();
     if (!displayId || !getHwComposer().isConnected(*displayId)) {
         return 0;
     }
@@ -1323,71 +1389,6 @@
     return config ? config->getVsyncPeriod() : 0;
 }
 
-void SurfaceFlinger::enableHardwareVsync() {
-    Mutex::Autolock _l(mHWVsyncLock);
-    if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
-        mPrimaryDispSync->beginResync();
-        mEventControlThread->setVsyncEnabled(true);
-        mPrimaryHWVsyncEnabled = true;
-    }
-}
-
-void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
-    Mutex::Autolock _l(mHWVsyncLock);
-
-    if (makeAvailable) {
-        mHWVsyncAvailable = true;
-        // TODO(b/113612090): This is silly, but necessary evil until we turn on the flag for good.
-        if (mUseScheduler) {
-            mScheduler->makeHWSyncAvailable(true);
-        }
-    } else if (!mHWVsyncAvailable) {
-        // Hardware vsync is not currently available, so abort the resync
-        // attempt for now
-        return;
-    }
-
-    if (period <= 0) {
-        return;
-    }
-
-    if (mUseScheduler) {
-        mScheduler->setVsyncPeriod(period);
-    } else {
-        mPrimaryDispSync->reset();
-        mPrimaryDispSync->setPeriod(period);
-
-        if (!mPrimaryHWVsyncEnabled) {
-            mPrimaryDispSync->beginResync();
-            mEventControlThread->setVsyncEnabled(true);
-            mPrimaryHWVsyncEnabled = true;
-        }
-    }
-}
-
-void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
-    Mutex::Autolock _l(mHWVsyncLock);
-    if (mPrimaryHWVsyncEnabled) {
-        mEventControlThread->setVsyncEnabled(false);
-        mPrimaryDispSync->endResync();
-        mPrimaryHWVsyncEnabled = false;
-    }
-    if (makeUnavailable) {
-        mHWVsyncAvailable = false;
-    }
-}
-
-void SurfaceFlinger::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
-    static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
-
-    const nsecs_t now = systemTime();
-    const nsecs_t last = lastResyncTime.exchange(now);
-
-    if (now - last > kIgnoreDelay) {
-        flinger.resyncToHardwareVsync(false, getVsyncPeriod());
-    }
-}
-
 void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
                                      int64_t timestamp) {
     ATRACE_NAME("SF onVsync");
@@ -1407,23 +1408,7 @@
         return;
     }
 
-    if (mUseScheduler) {
-        mScheduler->addResyncSample(timestamp);
-    } else {
-        bool needsHwVsync = false;
-        { // Scope for the lock
-            Mutex::Autolock _l(mHWVsyncLock);
-            if (mPrimaryHWVsyncEnabled) {
-                needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
-            }
-        }
-
-        if (needsHwVsync) {
-            enableHardwareVsync();
-        } else {
-            disableHardwareVsync(false);
-        }
-    }
+    mScheduler->addResyncSample(timestamp);
 }
 
 void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
@@ -1431,29 +1416,39 @@
     *compositorTiming = getBE().mCompositorTiming;
 }
 
-void SurfaceFlinger::setRefreshRateTo(float newFps) {
-    const auto displayId = getInternalDisplayId();
-    if (!displayId || mBootStage != BootStage::FINISHED) {
+void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate) {
+    mPhaseOffsets->setRefreshRateType(refreshRate);
+
+    const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+    mVsyncModulator.setPhaseOffsets(early, gl, late);
+
+    if (mBootStage != BootStage::FINISHED) {
         return;
     }
+
     // TODO(b/113612090): There should be a message queue flush here. Because this esentially
     // runs on a mainthread, we cannot call postMessageSync. This can be resolved in a better
     // manner, once the setActiveConfig is synchronous, and is executed at a known time in a
     // refresh cycle.
 
     // Don't do any updating if the current fps is the same as the new one.
-    const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
-    const nsecs_t currentVsyncPeriod = activeConfig->getVsyncPeriod();
+    const nsecs_t currentVsyncPeriod = getVsyncPeriod();
     if (currentVsyncPeriod == 0) {
         return;
     }
+
     // TODO(b/113612090): Consider having an enum value for correct refresh rates, rather than
     // floating numbers.
     const float currentFps = 1e9 / currentVsyncPeriod;
+    const float newFps = refreshRate == RefreshRateType::PERFORMANCE ? kPerformanceRefreshRate
+                                                                     : kDefaultRefreshRate;
     if (std::abs(currentFps - newFps) <= 1) {
         return;
     }
 
+    const auto displayId = getInternalDisplayIdLocked();
+    LOG_ALWAYS_FATAL_IF(!displayId);
+
     auto configs = getHwComposer().getConfigs(*displayId);
     for (int i = 0; i < configs.size(); i++) {
         const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
@@ -1464,12 +1459,7 @@
         // TODO(b/113612090): There should be a better way at determining which config
         // has the right refresh rate.
         if (std::abs(fps - newFps) <= 1) {
-            const auto display = getBuiltInDisplay(HWC_DISPLAY_PRIMARY);
-            if (!display) return;
-            // This is posted in async function to avoid deadlock when getDisplayDevice
-            // requires mStateLock.
-            setActiveConfigAsync(display, i);
-            ATRACE_INT("FPS", newFps);
+            setDesiredActiveConfig(getInternalDisplayTokenLocked(), i);
         }
     }
 }
@@ -1508,10 +1498,10 @@
     repaintEverythingForHWC();
 }
 
-void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) {
+void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) {
     ATRACE_CALL();
     Mutex::Autolock lock(mStateLock);
-    if (const auto displayId = getInternalDisplayId()) {
+    if (const auto displayId = getInternalDisplayIdLocked()) {
         getHwComposer().setVsyncEnabled(*displayId,
                                         enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
     }
@@ -1519,11 +1509,7 @@
 
 // Note: it is assumed the caller holds |mStateLock| when this is called
 void SurfaceFlinger::resetDisplayState() {
-    if (mUseScheduler) {
-        mScheduler->disableHardwareVsync(true);
-    } else {
-        disableHardwareVsync(true);
-    }
+    mScheduler->disableHardwareVsync(true);
     // Clear the drawing state so that the logic inside of
     // handleTransactionLocked will fire. It will determine the delta between
     // mCurrentState and mDrawingState and re-apply all changes when we make the
@@ -1533,6 +1519,7 @@
 }
 
 void SurfaceFlinger::updateVrFlinger() {
+    ATRACE_CALL();
     if (!mVrFlinger)
         return;
     bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
@@ -1552,7 +1539,18 @@
 
     sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
     LOG_ALWAYS_FATAL_IF(!display);
+
     const int currentDisplayPowerMode = display->getPowerMode();
+
+    // Clear out all the output layers from the composition engine for all
+    // displays before destroying the hardware composer interface. This ensures
+    // any HWC layers are destroyed through that interface before it becomes
+    // invalid.
+    for (const auto& [token, displayDevice] : mDisplays) {
+        displayDevice->getCompositionDisplay()->setOutputLayersOrderedByZ(
+                compositionengine::Output::OutputLayers());
+    }
+
     // This DisplayDevice will no longer be relevant once resetDisplayState() is
     // called below. Clear the reference now so we don't accidentally use it
     // later.
@@ -1590,20 +1588,14 @@
 
     // The present fences returned from vr_hwc are not an accurate
     // representation of vsync times.
-    if (mUseScheduler) {
-        mScheduler->setIgnorePresentFences(getHwComposer().isUsingVrComposer() ||
-                                           !hasSyncFramework);
-    } else {
-        mPrimaryDispSync->setIgnorePresentFences(getHwComposer().isUsingVrComposer() ||
-                                                 !hasSyncFramework);
-    }
+    mScheduler->setIgnorePresentFences(getHwComposer().isUsingVrComposer() || !hasSyncFramework);
 
     // Use phase of 0 since phase is not known.
     // Use latency of 0, which will snap to the ideal latency.
     DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
     setCompositorTimingSnapped(stats, 0);
 
-    resyncToHardwareVsync(false, vsyncPeriod);
+    mScheduler->resyncToHardwareVsync(false, vsyncPeriod);
 
     mRepaintEverything = true;
     setTransactionFlags(eDisplayTransactionNeeded);
@@ -1613,18 +1605,25 @@
     ATRACE_CALL();
     switch (what) {
         case MessageQueue::INVALIDATE: {
-            if (mUseScheduler) {
-                // This call is made each time SF wakes up and creates a new frame.
+            if (performSetActiveConfig()) {
+                break;
+            }
+
+            if (mUse90Hz && mUseSmart90ForVideo) {
+                // This call is made each time SF wakes up and creates a new frame. It is part
+                // of video detection feature.
                 mScheduler->incrementFrameCounter();
             }
-            bool frameMissed = !mHadClientComposition &&
-                    mPreviousPresentFence != Fence::NO_FENCE &&
-                    (mPreviousPresentFence->getSignalTime() ==
-                            Fence::SIGNAL_TIME_PENDING);
-            mFrameMissedCount += frameMissed;
-            ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+            bool frameMissed = mPreviousPresentFence != Fence::NO_FENCE &&
+                    (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled);
+            bool hwcFrameMissed = !mHadClientComposition && frameMissed;
             if (frameMissed) {
+                ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+                mFrameMissedCount++;
                 mTimeStats->incrementMissedFrames();
+            }
+            // For now, only propagate backpressure when missing a hwc frame.
+            if (hwcFrameMissed) {
                 if (mPropagateBackpressure) {
                     signalLayerUpdate();
                     break;
@@ -1638,6 +1637,10 @@
 
             bool refreshNeeded = handleMessageTransaction();
             refreshNeeded |= handleMessageInvalidate();
+
+            updateCursorAsync();
+            updateInputFlinger();
+
             refreshNeeded |= mRepaintEverything;
             if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
                 // Signal a refresh if a transaction modified the window state,
@@ -1655,6 +1658,7 @@
 }
 
 bool SurfaceFlinger::handleMessageTransaction() {
+    ATRACE_CALL();
     uint32_t transactionFlags = peekTransactionFlags();
 
     // Apply any ready transactions in the queues if there are still transactions that have not been
@@ -1705,26 +1709,9 @@
                 mHadClientComposition || getHwComposer().hasClientComposition(displayId);
     }
 
-    // Setup RenderEngine sync fences if native sync is supported.
-    if (getRenderEngine().useNativeFenceSync()) {
-        if (mHadClientComposition) {
-            base::unique_fd flushFence(getRenderEngine().flush());
-            ALOGE_IF(flushFence < 0, "Failed to flush RenderEngine!");
-            getBE().flushFence = new Fence(std::move(flushFence));
-        } else {
-            // Cleanup for hygiene.
-            getBE().flushFence = Fence::NO_FENCE;
-        }
-    }
-
     mVsyncModulator.onRefreshed(mHadClientComposition);
 
     getBE().mEndOfFrameCompositionInfo = std::move(getBE().mCompositionInfo);
-    for (const auto& [token, display] : mDisplays) {
-        for (auto& compositionInfo : getBE().mEndOfFrameCompositionInfo[token]) {
-            compositionInfo.hwc.hwcLayer = nullptr;
-        }
-    }
 
     mLayersWithQueuedFrames.clear();
 }
@@ -1732,7 +1719,19 @@
 
 bool SurfaceFlinger::handleMessageInvalidate() {
     ATRACE_CALL();
-    return handlePageFlip();
+    bool refreshNeeded = handlePageFlip();
+
+    if (mVisibleRegionsDirty) {
+        computeLayerBounds();
+    }
+
+    for (auto& layer : mLayersPendingRefresh) {
+        Region visibleReg;
+        visibleReg.set(layer->getScreenBounds());
+        invalidateLayerStack(layer, visibleReg);
+    }
+    mLayersPendingRefresh.clear();
+    return refreshNeeded;
 }
 
 void SurfaceFlinger::calculateWorkingSet() {
@@ -1753,16 +1752,14 @@
             for (size_t i = 0; i < currentLayers.size(); i++) {
                 const auto& layer = currentLayers[i];
 
-                if (!layer->hasHwcLayer(*displayId)) {
-                    if (!layer->createHwcLayer(&getHwComposer(), *displayId)) {
-                        layer->forceClientComposition(*displayId);
-                        continue;
-                    }
+                if (!layer->hasHwcLayer(displayDevice)) {
+                    layer->forceClientComposition(displayDevice);
+                    continue;
                 }
 
                 layer->setGeometry(displayDevice, i);
                 if (mDebugDisableHWC || mDebugRegion) {
-                    layer->forceClientComposition(*displayId);
+                    layer->forceClientComposition(displayDevice);
                 }
             }
         }
@@ -1782,34 +1779,35 @@
         }
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             if (layer->isHdrY410()) {
-                layer->forceClientComposition(*displayId);
+                layer->forceClientComposition(displayDevice);
             } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
                         layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
                        !profile->hasHDR10Support()) {
-                layer->forceClientComposition(*displayId);
+                layer->forceClientComposition(displayDevice);
             } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
                         layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
                        !profile->hasHLGSupport()) {
-                layer->forceClientComposition(*displayId);
+                layer->forceClientComposition(displayDevice);
             }
 
             // TODO(b/111562338) remove when composer 2.3 is shipped.
             if (layer->hasColorTransform()) {
-                layer->forceClientComposition(*displayId);
+                layer->forceClientComposition(displayDevice);
             }
 
             if (layer->getRoundedCornerState().radius > 0.0f) {
-                layer->forceClientComposition(*displayId);
+                layer->forceClientComposition(displayDevice);
             }
 
-            if (layer->getForceClientComposition(*displayId)) {
+            if (layer->getForceClientComposition(displayDevice)) {
                 ALOGV("[%s] Requesting Client composition", layer->getName().string());
-                layer->setCompositionType(*displayId, HWC2::Composition::Client);
+                layer->setCompositionType(displayDevice,
+                                          Hwc2::IComposerClient::Composition::CLIENT);
                 continue;
             }
 
             const auto& displayState = display->getState();
-            layer->setPerFrameData(*displayId, displayState.transform, displayState.viewport,
+            layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
                                    displayDevice->getSupportedPerFrameMetadata());
         }
 
@@ -1824,20 +1822,15 @@
 
     mDrawingState.colorMatrixChanged = false;
 
-    for (const auto& [token, display] : mDisplays) {
-        for (auto& layer : display->getVisibleLayersSortedByZ()) {
+    for (const auto& [token, displayDevice] : mDisplays) {
+        auto display = displayDevice->getCompositionDisplay();
+        for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             const auto displayId = display->getId();
-            layer->getBE().compositionInfo.compositionType = layer->getCompositionType(displayId);
-
-            if (displayId) {
-                if (!layer->setHwcLayer(*displayId)) {
-                    ALOGV("Need to create HWCLayer for %s", layer->getName().string());
-                }
-                layer->getBE().compositionInfo.hwc.displayId = *displayId;
-            }
-
+            auto& layerState = layer->getCompositionLayer()->editState().frontEnd;
+            layerState.compositionType = static_cast<Hwc2::IComposerClient::Composition>(
+                    layer->getCompositionType(displayDevice));
+            layer->getBE().compositionInfo.hwc.displayId = *displayId;
             getBE().mCompositionInfo[token].push_back(layer->getBE().compositionInfo);
-            layer->getBE().compositionInfo.hwc.hwcLayer = nullptr;
         }
     }
 }
@@ -1853,16 +1846,13 @@
 
     if (displayState.isEnabled) {
         // transform the dirty region into this screen's coordinate space
-        const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything);
+        const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
         if (!dirtyRegion.isEmpty()) {
+            base::unique_fd readyFence;
             // redraw the whole screen
-            doComposeSurfaces(displayDevice);
+            doComposeSurfaces(displayDevice, dirtyRegion, &readyFence);
 
-            // and draw the dirty region
-            auto& engine(getRenderEngine());
-            engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1);
-
-            display->getRenderSurface()->queueBuffer();
+            display->getRenderSurface()->queueBuffer(std::move(readyFence));
         }
     }
 
@@ -1888,7 +1878,7 @@
     if (CC_UNLIKELY(mLayerStats.isEnabled())) {
         for (const auto& [token, display] : mDisplays) {
             if (display->isPrimary()) {
-                mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(*display));
+                mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(display));
                 return;
             }
         }
@@ -2065,12 +2055,7 @@
 
     DisplayStatInfo stats;
     DEFINE_STACK_GUARD(stats);
-    if (mUseScheduler) {
-        mScheduler->getDisplayStatInfo(&stats);
-    } else {
-        stats.vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
-        stats.vsyncPeriod = mPrimaryDispSync->getPeriod();
-    }
+    mScheduler->getDisplayStatInfo(&stats);
 
     ASSERT_ON_STACK_GUARD();
 
@@ -2103,27 +2088,14 @@
 
     if (presentFenceTime->isValid()) {
         ASSERT_ON_STACK_GUARD();
-        if (mUseScheduler) {
-            mScheduler->addPresentFence(presentFenceTime);
-            ASSERT_ON_STACK_GUARD();
-        } else {
-            if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
-                enableHardwareVsync();
-            } else {
-                disableHardwareVsync(false);
-            }
-            ASSERT_ON_STACK_GUARD();
-        }
+        mScheduler->addPresentFence(presentFenceTime);
+        ASSERT_ON_STACK_GUARD();
     }
 
     if (!hasSyncFramework) {
         if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
             displayDevice->isPoweredOn()) {
-            if (mUseScheduler) {
-                mScheduler->enableHardwareVsync();
-            } else {
-                enableHardwareVsync();
-            }
+            mScheduler->enableHardwareVsync();
         }
     }
 
@@ -2206,10 +2178,29 @@
     mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
     mTransactionCompletedThread.sendCallbacks();
 
+    if (mLumaSampling) {
+        mRegionSamplingThread->sampleNow();
+    }
+
     ASSERT_ON_STACK_GUARD();
 }
 #pragma clang optimize on // b/119477596
 
+void SurfaceFlinger::computeLayerBounds() {
+    for (const auto& pair : mDisplays) {
+        const auto& displayDevice = pair.second;
+        const auto display = displayDevice->getCompositionDisplay();
+        for (const auto& layer : mDrawingState.layersSortedByZ) {
+            // only consider the layers on the given layer stack
+            if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+                continue;
+            }
+
+            layer->computeBounds(displayDevice->getViewport().toFloatRect(), ui::Transform());
+        }
+    }
+}
+
 void SurfaceFlinger::rebuildLayerStacks() {
     ATRACE_CALL();
     ALOGV("rebuildLayerStacks");
@@ -2251,42 +2242,42 @@
                         return;
                     }
 
-                    bool hwcLayerDestroyed = false;
                     const auto displayId = displayDevice->getId();
                     sp<compositionengine::LayerFE> layerFE = compositionLayer->getLayerFE();
                     LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr);
 
+                    bool needsOutputLayer = false;
+
                     if (display->belongsInOutput(layer->getLayerStack(),
                                                  layer->getPrimaryDisplayOnly())) {
                         Region drawRegion(tr.transform(
                                 layer->visibleNonTransparentRegion));
                         drawRegion.andSelf(bounds);
                         if (!drawRegion.isEmpty()) {
-                            layersSortedByZ.emplace_back(
-                                    display->getOrCreateOutputLayer(layer->getCompositionLayer(),
-                                                                    layerFE));
-
-                            deprecated_layersSortedByZ.add(layer);
-                        } else {
-                            // Clear out the HWC layer if this layer was
-                            // previously visible, but no longer is
-                            hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
+                            needsOutputLayer = true;
                         }
-                    } else {
-                        // WM changes display->layerStack upon sleep/awake.
-                        // Here we make sure we delete the HWC layers even if
-                        // WM changed their layer stack.
-                        hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
                     }
 
-                    // If a layer is not going to get a release fence because
-                    // it is invisible, but it is also going to release its
-                    // old buffer, add it to the list of layers needing
-                    // fences.
-                    if (hwcLayerDestroyed) {
-                        auto found = std::find(mLayersWithQueuedFrames.cbegin(),
-                                mLayersWithQueuedFrames.cend(), layer);
-                        if (found != mLayersWithQueuedFrames.cend()) {
+                    if (needsOutputLayer) {
+                        layersSortedByZ.emplace_back(
+                                display->getOrCreateOutputLayer(displayId, compositionLayer,
+                                                                layerFE));
+                        deprecated_layersSortedByZ.add(layer);
+
+                        auto& outputLayerState = layersSortedByZ.back()->editState();
+                        outputLayerState.visibleRegion =
+                                tr.transform(layer->visibleRegion.intersect(displayState.viewport));
+                    } else if (displayId) {
+                        // For layers that are being removed from a HWC display,
+                        // and that have queued frames, add them to a a list of
+                        // released layers so we can properly set a fence.
+                        bool hasExistingOutputLayer =
+                                display->getOutputLayerForLayer(compositionLayer.get()) != nullptr;
+                        bool hasQueuedFrames = std::find(mLayersWithQueuedFrames.cbegin(),
+                                                         mLayersWithQueuedFrames.cend(),
+                                                         layer) != mLayersWithQueuedFrames.cend();
+
+                        if (hasExistingOutputLayer && hasQueuedFrames) {
                             layersNeedingFences.add(layer);
                         }
                     }
@@ -2336,10 +2327,12 @@
                 break;
             case Dataspace::BT2020_PQ:
             case Dataspace::BT2020_ITU_PQ:
+                bestDataSpace = Dataspace::DISPLAY_P3;
                 *outHdrDataSpace = Dataspace::BT2020_PQ;
                 break;
             case Dataspace::BT2020_HLG:
             case Dataspace::BT2020_ITU_HLG:
+                bestDataSpace = Dataspace::DISPLAY_P3;
                 // When there's mixed PQ content and HLG content, we set the HDR
                 // data space to be BT2020_PQ and convert HLG to PQ.
                 if (*outHdrDataSpace == Dataspace::UNKNOWN) {
@@ -2369,6 +2362,17 @@
 
     auto* profile = display->getCompositionDisplay()->getDisplayColorProfile();
 
+    switch (mForceColorMode) {
+        case ColorMode::SRGB:
+            bestDataSpace = Dataspace::V0_SRGB;
+            break;
+        case ColorMode::DISPLAY_P3:
+            bestDataSpace = Dataspace::DISPLAY_P3;
+            break;
+        default:
+            break;
+    }
+
     // respect hdrDataSpace only when there is no legacy HDR support
     const bool isHdr =
             hdrDataSpace != Dataspace::UNKNOWN && !profile->hasLegacyHdrSupport(hdrDataSpace);
@@ -2397,7 +2401,7 @@
     auto display = displayDevice->getCompositionDisplay();
     const auto& displayState = display->getState();
 
-    bool dirty = !display->getPhysicalSpaceDirtyRegion(false).isEmpty();
+    bool dirty = !display->getDirtyRegion(false).isEmpty();
     bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
     bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
 
@@ -2433,8 +2437,7 @@
         return;
     }
 
-    status_t result = display->getRenderSurface()->prepareFrame(
-            getBE().mCompositionInfo[displayDevice->getDisplayToken()]);
+    status_t result = display->getRenderSurface()->prepareFrame();
     ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
              displayDevice->getDebugName().c_str(), result, strerror(-result));
 }
@@ -2448,7 +2451,7 @@
 
     if (displayState.isEnabled) {
         // transform the dirty region into this screen's coordinate space
-        const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything);
+        const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
 
         // repaint the framebuffer (if needed)
         doDisplayComposition(displayDevice, dirtyRegion);
@@ -2492,9 +2495,10 @@
             // The layer buffer from the previous frame (if any) is released
             // by HWC only when the release fence from this frame (if any) is
             // signaled.  Always get the release fence from HWC first.
-            if (displayId && layer->hasHwcLayer(*displayId)) {
-                releaseFence = getHwComposer().getLayerReleaseFence(*displayId,
-                                                                    layer->getHwcLayer(*displayId));
+            if (displayId && layer->hasHwcLayer(displayDevice)) {
+                releaseFence =
+                        getHwComposer().getLayerReleaseFence(*displayId,
+                                                             layer->getHwcLayer(displayDevice));
             }
 
             // If the layer was client composited in the previous frame, we
@@ -2502,7 +2506,8 @@
             // Since we do not track that, always merge with the current
             // client target acquire fence when it is available, even though
             // this is suboptimal.
-            if (layer->getCompositionType(displayId) == HWC2::Composition::Client) {
+            if (layer->getCompositionType(displayDevice) ==
+                Hwc2::IComposerClient::Composition::CLIENT) {
                 releaseFence =
                         Fence::merge("LayerRelease", releaseFence,
                                      display->getRenderSurface()->getClientTargetAcquireFence());
@@ -2596,15 +2601,9 @@
     mPendingHotplugEvents.clear();
 }
 
-void SurfaceFlinger::dispatchDisplayHotplugEvent(EventThread::DisplayType displayType,
-                                                 bool connected) {
-    if (mUseScheduler) {
-        mScheduler->hotplugReceived(mAppConnectionHandle, displayType, connected);
-        mScheduler->hotplugReceived(mSfConnectionHandle, displayType, connected);
-    } else {
-        mEventThread->onHotplugReceived(displayType, connected);
-        mSFEventThread->onHotplugReceived(displayType, connected);
-    }
+void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
+    mScheduler->hotplugReceived(mAppConnectionHandle, displayId, connected);
+    mScheduler->hotplugReceived(mSfConnectionHandle, displayId, connected);
 }
 
 sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
@@ -2619,7 +2618,7 @@
     creationArgs.hasWideColorGamut = false;
     creationArgs.supportedPerFrameMetadata = 0;
 
-    const bool isInternalDisplay = displayId && displayId == getInternalDisplayId();
+    const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
     creationArgs.isPrimary = isInternalDisplay;
 
     if (useColorManagement && displayId) {
@@ -2702,19 +2701,18 @@
         for (size_t i = 0; i < dc;) {
             const ssize_t j = curr.indexOfKey(draw.keyAt(i));
             if (j < 0) {
-                // Save display IDs before disconnecting.
-                const auto internalDisplayId = getInternalDisplayId();
-                const auto externalDisplayId = getExternalDisplayId();
-
                 // in drawing state but not in current state
                 if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
+                    // Save display ID before disconnecting.
+                    const auto displayId = display->getId();
                     display->disconnect();
+
+                    if (!display->isVirtual()) {
+                        LOG_ALWAYS_FATAL_IF(!displayId);
+                        dispatchDisplayHotplugEvent(displayId->value, false);
+                    }
                 }
-                if (internalDisplayId && internalDisplayId == draw[i].displayId) {
-                    dispatchDisplayHotplugEvent(EventThread::DisplayType::Primary, false);
-                } else if (externalDisplayId && externalDisplayId == draw[i].displayId) {
-                    dispatchDisplayHotplugEvent(EventThread::DisplayType::External, false);
-                }
+
                 mDisplays.erase(draw.keyAt(i));
             } else {
                 // this display is in both lists. see if something changed.
@@ -2817,12 +2815,7 @@
                                                                     dispSurface, producer));
                     if (!state.isVirtual()) {
                         LOG_ALWAYS_FATAL_IF(!displayId);
-
-                        if (displayId == getInternalDisplayId()) {
-                            dispatchDisplayHotplugEvent(EventThread::DisplayType::Primary, true);
-                        } else if (displayId == getExternalDisplayId()) {
-                            dispatchDisplayHotplugEvent(EventThread::DisplayType::External, true);
-                        }
+                        dispatchDisplayHotplugEvent(displayId->value, true);
                     }
                 }
             }
@@ -2844,7 +2837,6 @@
      * (perform the transaction for each of them if needed)
      */
 
-    bool inputChanged = false;
     if (transactionFlags & eTraversalNeeded) {
         mCurrentState.traverseInZOrder([&](Layer* layer) {
             uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
@@ -2855,7 +2847,7 @@
                 mVisibleRegionsDirty = true;
 
             if (flags & Layer::eInputInfoChanged) {
-                inputChanged = true;
+                mInputInfoChanged = true;
             }
         });
     }
@@ -2956,33 +2948,36 @@
         mDrawingState.traverseInZOrder([&](Layer* layer) {
             if (mLayersPendingRemoval.indexOf(layer) >= 0) {
                 // this layer is not visible anymore
-                // TODO: we could traverse the tree from front to back and
-                //       compute the actual visible region
-                // TODO: we could cache the transformed region
                 Region visibleReg;
-                visibleReg.set(layer->computeScreenBounds());
+                visibleReg.set(layer->getScreenBounds());
                 invalidateLayerStack(layer, visibleReg);
             }
         });
     }
 
+    commitInputWindowCommands();
     commitTransaction();
-
-    if (inputChanged || mVisibleRegionsDirty) {
-        updateInputWindows();
-    }
-    executeInputWindowCommands();
-
-    updateCursorAsync();
 }
 
-void SurfaceFlinger::updateInputWindows() {
+void SurfaceFlinger::updateInputFlinger() {
     ATRACE_CALL();
-
-    if (mInputFlinger == nullptr) {
+    if (!mInputFlinger) {
         return;
     }
 
+    if (mVisibleRegionsDirty || mInputInfoChanged) {
+        mInputInfoChanged = false;
+        updateInputWindowInfo();
+    } else if (mInputWindowCommands.syncInputWindows) {
+        // If the caller requested to sync input windows, but there are no
+        // changes to input windows, notify immediately.
+        setInputWindowsFinished();
+    }
+
+    executeInputWindowCommands();
+}
+
+void SurfaceFlinger::updateInputWindowInfo() {
     Vector<InputWindowInfo> inputHandles;
 
     mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
@@ -2992,14 +2987,18 @@
             inputHandles.add(layer->fillInputInfo());
         }
     });
-    mInputFlinger->setInputWindows(inputHandles);
+
+    mInputFlinger->setInputWindows(inputHandles,
+                                   mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener
+                                                                         : nullptr);
+}
+
+void SurfaceFlinger::commitInputWindowCommands() {
+    mInputWindowCommands.merge(mPendingInputWindowCommands);
+    mPendingInputWindowCommands.clear();
 }
 
 void SurfaceFlinger::executeInputWindowCommands() {
-    if (!mInputFlinger) {
-        return;
-    }
-
     for (const auto& transferTouchFocusCommand : mInputWindowCommands.transferTouchFocusCommands) {
         if (transferTouchFocusCommand.fromToken != nullptr &&
             transferTouchFocusCommand.toToken != nullptr &&
@@ -3027,11 +3026,8 @@
 
 void SurfaceFlinger::latchAndReleaseBuffer(const sp<Layer>& layer) {
     if (layer->hasReadyFrame()) {
-        const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime();
-        if (layer->shouldPresentNow(expectedPresentTime)) {
-            bool ignored = false;
-            layer->latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
-        }
+        bool ignored = false;
+        layer->latchBuffer(ignored, systemTime());
     }
     layer->releasePendingBuffer(systemTime());
 }
@@ -3044,12 +3040,8 @@
             recordBufferingStats(l->getName().string(),
                     l->getOccupancyHistory(true));
 
-            // We need to release the HWC layers when the Layer is removed
-            // from the current state otherwise the HWC layer just continues
-            // showing at its last configured state until we eventually
-            // abandon the buffer queue.
+            // Ensure any buffers set to display on any children are released.
             if (l->isRemovedFromCurrentState()) {
-                l->destroyHwcLayersForAllDisplays();
                 latchAndReleaseBuffer(l);
             }
         }
@@ -3127,7 +3119,7 @@
         // handle hidden surfaces by setting the visible region to empty
         if (CC_LIKELY(layer->isVisible())) {
             const bool translucent = !layer->isOpaque(s);
-            Rect bounds(layer->computeScreenBounds());
+            Rect bounds(layer->getScreenBounds());
 
             visibleRegion.set(bounds);
             ui::Transform tr = layer->getTransform();
@@ -3259,7 +3251,8 @@
     mDrawingState.traverseInZOrder([&](Layer* layer) {
         if (layer->hasReadyFrame()) {
             frameQueued = true;
-            const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime();
+            nsecs_t expectedPresentTime;
+            expectedPresentTime = mScheduler->expectedPresentTime();
             if (layer->shouldPresentNow(expectedPresentTime)) {
                 mLayersWithQueuedFrames.push_back(layer);
             } else {
@@ -3276,27 +3269,18 @@
         Mutex::Autolock lock(mStateLock);
 
         for (auto& layer : mLayersWithQueuedFrames) {
-            const Region dirty(layer->latchBuffer(visibleRegions, latchTime, getBE().flushFence));
+            if (layer->latchBuffer(visibleRegions, latchTime)) {
+                mLayersPendingRefresh.push_back(layer);
+            }
             layer->useSurfaceDamage();
-            invalidateLayerStack(layer, dirty);
             if (layer->isBufferLatched()) {
                 newDataLatched = true;
             }
         }
     }
 
-    // Clear the renderengine fence here...
-    // downstream code assumes that a cleared fence == NO_FENCE, so reassign to
-    // clear instead of sp::clear.
-    getBE().flushFence = Fence::NO_FENCE;
-
     mVisibleRegionsDirty |= visibleRegions;
 
-    if (visibleRegions) {
-        // Update input window info if the layer receives its first buffer.
-        updateInputWindows();
-    }
-
     // If we will need to wake up at some time in the future to deal with a
     // queued frame that shouldn't be displayed during this vsync period, wake
     // up during the next vsync period to check again.
@@ -3322,7 +3306,6 @@
 void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& displayDevice,
                                           const Region& inDirtyRegion) {
     auto display = displayDevice->getCompositionDisplay();
-
     // We only need to actually compose the display if:
     // 1) It is being handled by hardware composer, which may need this to
     //    keep its virtual display state machine in sync, or
@@ -3333,13 +3316,16 @@
     }
 
     ALOGV("doDisplayComposition");
-    if (!doComposeSurfaces(displayDevice)) return;
+    base::unique_fd readyFence;
+    if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return;
 
     // swap buffers (presentation)
-    display->getRenderSurface()->queueBuffer();
+    display->getRenderSurface()->queueBuffer(std::move(readyFence));
 }
 
-bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) {
+bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice,
+                                       const Region& debugRegion, base::unique_fd* readyFence) {
+    ATRACE_CALL();
     ALOGV("doComposeSurfaces");
 
     auto display = displayDevice->getCompositionDisplay();
@@ -3354,14 +3340,15 @@
     mat4 colorMatrix;
     bool applyColorMatrix = false;
 
-    // Framebuffer will live in this scope for GPU composition.
-    std::unique_ptr<renderengine::BindNativeBufferAsFramebuffer> fbo;
+    renderengine::DisplaySettings clientCompositionDisplay;
+    std::vector<renderengine::LayerSettings> clientCompositionLayers;
+    sp<GraphicBuffer> buf;
+    base::unique_fd fd;
 
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
-        sp<GraphicBuffer> buf = display->getRenderSurface()->dequeueBuffer();
-
+        buf = display->getRenderSurface()->dequeueBuffer(&fd);
         if (buf == nullptr) {
             ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
                   "client composition for this frame",
@@ -3369,24 +3356,29 @@
             return false;
         }
 
-        // Bind the framebuffer in this scope.
-        fbo = std::make_unique<renderengine::BindNativeBufferAsFramebuffer>(getRenderEngine(),
-                                                                            buf->getNativeBuffer());
-
-        if (fbo->getStatus() != NO_ERROR) {
-            ALOGW("Binding buffer for display [%s] failed with status: %d",
-                  displayDevice->getDisplayName().c_str(), fbo->getStatus());
-            return false;
-        }
+        clientCompositionDisplay.physicalDisplay = displayState.scissor;
+        clientCompositionDisplay.clip = displayState.scissor;
+        const ui::Transform& displayTransform = displayState.transform;
+        mat4 m;
+        m[0][0] = displayTransform[0][0];
+        m[0][1] = displayTransform[0][1];
+        m[0][3] = displayTransform[0][2];
+        m[1][0] = displayTransform[1][0];
+        m[1][1] = displayTransform[1][1];
+        m[1][3] = displayTransform[1][2];
+        m[3][0] = displayTransform[2][0];
+        m[3][1] = displayTransform[2][1];
+        m[3][3] = displayTransform[2][2];
+        clientCompositionDisplay.globalTransform = m;
 
         const auto* profile = display->getDisplayColorProfile();
         Dataspace outputDataspace = Dataspace::UNKNOWN;
         if (profile->hasWideColorGamut()) {
             outputDataspace = displayState.dataspace;
         }
-        getRenderEngine().setOutputDataSpace(outputDataspace);
-        getRenderEngine().setDisplayMaxLuminance(
-                profile->getHdrCapabilities().getDesiredMaxLuminance());
+        clientCompositionDisplay.outputDataspace = outputDataspace;
+        clientCompositionDisplay.maxLuminance =
+                profile->getHdrCapabilities().getDesiredMaxLuminance();
 
         const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId);
         const bool skipClientColorTransform =
@@ -3397,44 +3389,7 @@
         // Compute the global color transform matrix.
         applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
         if (applyColorMatrix) {
-            colorMatrix = mDrawingState.colorMatrix;
-        }
-
-        display->getRenderSurface()->setViewportAndProjection();
-
-        // Never touch the framebuffer if we don't have any framebuffer layers
-        if (hasDeviceComposition) {
-            // when using overlays, we assume a fully transparent framebuffer
-            // NOTE: we could reduce how much we need to clear, for instance
-            // remove where there are opaque FB layers. however, on some
-            // GPUs doing a "clean slate" clear might be more efficient.
-            // We'll revisit later if needed.
-            getRenderEngine().clearWithColor(0, 0, 0, 0);
-        } else {
-            // we start with the whole screen area and remove the scissor part
-            // we're left with the letterbox region
-            // (common case is that letterbox ends-up being empty)
-            const Region letterbox = bounds.subtract(displayState.scissor);
-
-            // compute the area to clear
-            const Region region = displayState.undefinedRegion.merge(letterbox);
-
-            // screen is already cleared here
-            if (!region.isEmpty()) {
-                // can happen with SurfaceView
-                drawWormhole(region);
-            }
-        }
-
-        const Rect& bounds = displayState.bounds;
-        const Rect& scissor = displayState.scissor;
-        if (scissor != bounds) {
-            // scissor doesn't match the screen's dimensions, so we
-            // need to clear everything outside of it and enable
-            // the GL scissor so we don't draw anything where we shouldn't
-
-            // enable scissor for this frame
-            getRenderEngine().setScissor(scissor);
+            clientCompositionDisplay.colorTransform = colorMatrix;
         }
     }
 
@@ -3443,41 +3398,48 @@
      */
 
     ALOGV("Rendering client layers");
-    const ui::Transform& displayTransform = displayState.transform;
     bool firstLayer = true;
+    Region clearRegion = Region::INVALID_REGION;
     for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-        const Region clip(bounds.intersect(displayTransform.transform(layer->visibleRegion)));
+        const Region viewportRegion(displayState.viewport);
+        const Region clip(viewportRegion.intersect(layer->visibleRegion));
         ALOGV("Layer: %s", layer->getName().string());
-        ALOGV("  Composition type: %s", to_string(layer->getCompositionType(displayId)).c_str());
+        ALOGV("  Composition type: %s", toString(layer->getCompositionType(displayDevice)).c_str());
         if (!clip.isEmpty()) {
-            switch (layer->getCompositionType(displayId)) {
-                case HWC2::Composition::Cursor:
-                case HWC2::Composition::Device:
-                case HWC2::Composition::Sideband:
-                case HWC2::Composition::SolidColor: {
+            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(*displayId) && !firstLayer &&
+                    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
-                        layer->clearWithOpenGL(renderArea);
+                        renderengine::LayerSettings layerSettings;
+                        Region dummyRegion;
+                        bool prepared = layer->prepareClientLayer(renderArea, clip, dummyRegion,
+                                                                  layerSettings);
+
+                        if (prepared) {
+                            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::Composition::Client: {
-                    if (layer->hasColorTransform()) {
-                        mat4 tmpMatrix;
-                        if (applyColorMatrix) {
-                            tmpMatrix = mDrawingState.colorMatrix;
-                        }
-                        tmpMatrix *= layer->getColorTransform();
-                        getRenderEngine().setColorTransform(tmpMatrix);
-                    } else {
-                        getRenderEngine().setColorTransform(colorMatrix);
+                case Hwc2::IComposerClient::Composition::CLIENT: {
+                    renderengine::LayerSettings layerSettings;
+                    bool prepared =
+                            layer->prepareClientLayer(renderArea, clip, clearRegion, layerSettings);
+                    if (prepared) {
+                        clientCompositionLayers.push_back(layerSettings);
                     }
-                    layer->draw(renderArea, clip);
                     break;
                 }
                 default:
@@ -3491,12 +3453,22 @@
 
     // Perform some cleanup steps if we used client composition.
     if (hasClientComposition) {
-        getRenderEngine().setColorTransform(mat4());
-        getRenderEngine().disableScissor();
-        display->getRenderSurface()->finishBuffer();
-        // Clear out error flags here so that we don't wait until next
-        // composition to log.
-        getRenderEngine().checkErrors();
+        clientCompositionDisplay.clearRegion = clearRegion;
+        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);
+            }
+        }
+        getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers,
+                                     buf->getNativeBuffer(), std::move(fd), readyFence);
     }
     return true;
 }
@@ -3578,11 +3550,12 @@
         auto& [applyToken, transactionQueue] = *it;
 
         while (!transactionQueue.empty()) {
-            const auto& [states, displays, flags, desiredPresentTime] = transactionQueue.front();
+            const auto& [states, displays, flags, desiredPresentTime, privileged] =
+                    transactionQueue.front();
             if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
                 break;
             }
-            applyTransactionState(states, displays, flags, mInputWindowCommands);
+            applyTransactionState(states, displays, flags, mPendingInputWindowCommands, privileged);
             transactionQueue.pop();
         }
 
@@ -3615,7 +3588,7 @@
 
 bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
                                                    const Vector<ComposerState>& states) {
-    const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime();
+    nsecs_t expectedPresentTime = mScheduler->expectedPresentTime();
     // Do not present if the desiredPresentTime has not passed unless it is more than one second
     // in the future. We ignore timestamps more than 1 second in the future for stability reasons.
     if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime &&
@@ -3641,6 +3614,9 @@
                                          const InputWindowCommands& inputWindowCommands,
                                          int64_t desiredPresentTime) {
     ATRACE_CALL();
+
+    bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess();
+
     Mutex::Autolock _l(mStateLock);
 
     if (containsAnyInvalidClientState(states)) {
@@ -3650,17 +3626,19 @@
     // If its TransactionQueue already has a pending TransactionState or if it is pending
     if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
         !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
-        mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime);
+        mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
+                privileged);
         setTransactionFlags(eTransactionNeeded);
         return;
     }
 
-    applyTransactionState(states, displays, flags, inputWindowCommands);
+    applyTransactionState(states, displays, flags, inputWindowCommands, privileged);
 }
 
 void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states,
                                            const Vector<DisplayState>& displays, uint32_t flags,
-                                           const InputWindowCommands& inputWindowCommands) {
+                                           const InputWindowCommands& inputWindowCommands,
+                                           bool privileged) {
     uint32_t transactionFlags = 0;
 
     if (flags & eAnimation) {
@@ -3685,7 +3663,7 @@
 
     uint32_t clientStateFlags = 0;
     for (const ComposerState& state : states) {
-        clientStateFlags |= setClientStateLocked(state);
+        clientStateFlags |= setClientStateLocked(state, privileged);
     }
     // If the state doesn't require a traversal and there are callbacks, send them now
     if (!(clientStateFlags & eTraversalNeeded)) {
@@ -3722,13 +3700,16 @@
         if (flags & eAnimation) {
             mAnimTransactionPending = true;
         }
-        while (mTransactionPending) {
+
+        mPendingSyncInputWindows = mPendingInputWindowCommands.syncInputWindows;
+        while (mTransactionPending || mPendingSyncInputWindows) {
             status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
             if (CC_UNLIKELY(err != NO_ERROR)) {
                 // just in case something goes wrong in SF, return to the
                 // called after a few seconds.
                 ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
                 mTransactionPending = false;
+                mPendingSyncInputWindows = false;
                 break;
             }
         }
@@ -3783,7 +3764,7 @@
     return flags;
 }
 
-bool callingThreadHasUnscopedSurfaceFlingerAccess() {
+bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess() {
     IPCThreadState* ipc = IPCThreadState::self();
     const int pid = ipc->getCallingPid();
     const int uid = ipc->getCallingUid();
@@ -3794,7 +3775,8 @@
     return true;
 }
 
-uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState) {
+uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState,
+        bool privileged) {
     const layer_state_t& s = composerState.state;
     sp<Client> client(static_cast<Client*>(composerState.client.get()));
 
@@ -3895,7 +3877,7 @@
         // of cropped areas, we need to prevent non-root clients without permission ACCESS_SURFACE_FLINGER
         // (a.k.a. everyone except WindowManager and tests) from setting non rectangle preserving
         // transformations.
-        if (layer->setMatrix(s.matrix, callingThreadHasUnscopedSurfaceFlingerAccess()))
+        if (layer->setMatrix(s.matrix, privileged))
             flags |= eTraversalNeeded;
     }
     if (what & layer_state_t::eTransparentRegionChanged) {
@@ -4045,7 +4027,11 @@
         flags |= eTraversalNeeded;
     }
 
-    mInputWindowCommands.merge(inputWindowCommands);
+    if (inputWindowCommands.syncInputWindows) {
+        flags |= eTraversalNeeded;
+    }
+
+    mPendingInputWindowCommands.merge(inputWindowCommands);
     return flags;
 }
 
@@ -4261,7 +4247,7 @@
     d.width = 0;
     d.height = 0;
     displays.add(d);
-    setTransactionState(state, displays, 0, nullptr, mInputWindowCommands, -1);
+    setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1);
 
     setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
 
@@ -4306,12 +4292,8 @@
         // Turn on the display
         getHwComposer().setPowerMode(*displayId, mode);
         if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
-            if (mUseScheduler) {
-                mScheduler->onScreenAcquired(mAppConnectionHandle);
-            } else {
-                mEventThread->onScreenAcquired();
-            }
-            resyncToHardwareVsync(true, getVsyncPeriod());
+            mScheduler->onScreenAcquired(mAppConnectionHandle);
+            mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
         }
 
         mVisibleRegionsDirty = true;
@@ -4331,16 +4313,8 @@
         }
 
         if (display->isPrimary() && currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
-            if (mUseScheduler) {
-                mScheduler->disableHardwareVsync(true);
-            } else {
-                disableHardwareVsync(true); // also cancels any in-progress resync
-            }
-            if (mUseScheduler) {
-                mScheduler->onScreenReleased(mAppConnectionHandle);
-            } else {
-                mEventThread->onScreenReleased();
-            }
+            mScheduler->disableHardwareVsync(true);
+            mScheduler->onScreenReleased(mAppConnectionHandle);
         }
 
         getHwComposer().setPowerMode(*displayId, mode);
@@ -4351,26 +4325,14 @@
         // Update display while dozing
         getHwComposer().setPowerMode(*displayId, mode);
         if (display->isPrimary() && currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
-            if (mUseScheduler) {
-                mScheduler->onScreenAcquired(mAppConnectionHandle);
-            } else {
-                mEventThread->onScreenAcquired();
-            }
-            resyncToHardwareVsync(true, getVsyncPeriod());
+            mScheduler->onScreenAcquired(mAppConnectionHandle);
+            mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
         }
     } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
         // Leave display going to doze
         if (display->isPrimary()) {
-            if (mUseScheduler) {
-                mScheduler->disableHardwareVsync(true);
-            } else {
-                disableHardwareVsync(true); // also cancels any in-progress resync
-            }
-            if (mUseScheduler) {
-                mScheduler->onScreenReleased(mAppConnectionHandle);
-            } else {
-                mEventThread->onScreenReleased();
-            }
+            mScheduler->disableHardwareVsync(true);
+            mScheduler->onScreenReleased(mAppConnectionHandle);
         }
         getHwComposer().setPowerMode(*displayId, mode);
     } else {
@@ -4380,7 +4342,7 @@
 
     if (display->isPrimary()) {
         mTimeStats->setPowerMode(mode);
-        if (mUseScheduler && mRefreshRateStats) {
+        if (mRefreshRateStats) {
             // Update refresh rate stats.
             mRefreshRateStats->setPowerMode(mode);
         }
@@ -4436,10 +4398,11 @@
                 {"--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) { mPrimaryDispSync->dump(s); })},
+                {"--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-composition"s, dumper(&SurfaceFlinger::dumpFrameCompositionInfo)},
                 {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
                 {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
                 {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
@@ -4536,13 +4499,10 @@
                   "    present offset: %9" PRId64 " ns\t     VSYNC period: %9" PRId64 " ns\n\n",
                   dispSyncPresentTimeOffset, getVsyncPeriod());
 
-    StringAppendF(&result, "Scheduler: %s\n\n", mUseScheduler ? "enabled" : "disabled");
-
-    if (mUseScheduler) {
-        mScheduler->dump(mAppConnectionHandle, result);
-    } else {
-        mEventThread->dump(result);
-    }
+    StringAppendF(&result, "Scheduler enabled. 90Hz feature: %s\n", mUse90Hz ? "on" : "off");
+    StringAppendF(&result, "+  Smart 90 for video detection: %s\n\n",
+                  mUseSmart90ForVideo ? "on" : "off");
+    mScheduler->dump(mAppConnectionHandle, result);
 }
 
 void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const {
@@ -4693,23 +4653,6 @@
     result.append("\n");
 }
 
-void SurfaceFlinger::dumpFrameCompositionInfo(std::string& result) const {
-    for (const auto& [token, display] : mDisplays) {
-        const auto it = getBE().mEndOfFrameCompositionInfo.find(token);
-        if (it == getBE().mEndOfFrameCompositionInfo.end()) {
-            continue;
-        }
-
-        const auto& compositionInfoList = it->second;
-        StringAppendF(&result, "%s\n", display->getDebugName().c_str());
-        StringAppendF(&result, "numComponents: %zu\n", compositionInfoList.size());
-        for (const auto& compositionInfo : compositionInfoList) {
-            compositionInfo.dump(result, nullptr);
-            result.append("\n");
-        }
-    }
-}
-
 LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet) const {
     LayersProto layersProto;
     const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
@@ -4722,26 +4665,27 @@
     return layersProto;
 }
 
-LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(const DisplayDevice& displayDevice) const {
+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());
+    resolution->set_w(displayDevice->getWidth());
+    resolution->set_h(displayDevice->getHeight());
 
-    auto display = displayDevice.getCompositionDisplay();
+    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();
+    const auto displayId = displayDevice->getId();
     LOG_ALWAYS_FATAL_IF(!displayId);
     mDrawingState.traverseInZOrder([&](Layer* layer) {
-        if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(*displayId)) {
+        if (!layer->visibleRegion.isEmpty() && !display->getOutputLayersOrderedByZ().empty()) {
             LayerProto* layerProto = layersProto.add_layers();
-            layer->writeToProto(layerProto, *displayId);
+            layer->writeToProto(layerProto, displayDevice);
         }
     });
 
@@ -4810,10 +4754,6 @@
         result.append("\n");
     }
 
-    result.append("\nFrame-Composition information:\n");
-    dumpFrameCompositionInfo(result);
-    result.append("\n");
-
     /*
      * Dump Display state
      */
@@ -4847,7 +4787,7 @@
                   "  gpu_to_cpu_unsupported    : %d\n",
                   mTransactionFlags.load(), !mGpuToCpuSupported);
 
-    if (const auto displayId = getInternalDisplayId();
+    if (const auto displayId = getInternalDisplayIdLocked();
         displayId && getHwComposer().isConnected(*displayId)) {
         const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
         StringAppendF(&result,
@@ -4877,7 +4817,9 @@
 
         StringAppendF(&result, "Display %s HWC layers:\n", to_string(*displayId).c_str());
         Layer::miniDumpHeader(result);
-        mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, *displayId); });
+        const sp<DisplayDevice> displayDevice = display;
+        mCurrentState.traverseInZOrder(
+                [&](Layer* layer) { layer->miniDump(result, displayDevice); });
         result.append("\n");
     }
 
@@ -4909,11 +4851,9 @@
     /**
      * Scheduler dump state.
      */
-    if (mUseScheduler) {
-        result.append("\nScheduler state:\n");
-        result.append(mScheduler->doDump() + "\n");
-        result.append(mRefreshRateStats->doDump() + "\n");
-    }
+    result.append("\nScheduler state:\n");
+    result.append(mScheduler->doDump() + "\n");
+    result.append(mRefreshRateStats->doDump() + "\n");
 }
 
 const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
@@ -4999,7 +4939,8 @@
         // information, so it is OK to pass them.
         case AUTHENTICATE_SURFACE:
         case GET_ACTIVE_CONFIG:
-        case GET_BUILT_IN_DISPLAY:
+        case GET_PHYSICAL_DISPLAY_IDS:
+        case GET_PHYSICAL_DISPLAY_TOKEN:
         case GET_DISPLAY_COLOR_MODES:
         case GET_DISPLAY_NATIVE_PRIMARIES:
         case GET_DISPLAY_CONFIGS:
@@ -5016,7 +4957,9 @@
             return OK;
         }
         case CAPTURE_LAYERS:
-        case CAPTURE_SCREEN: {
+        case CAPTURE_SCREEN:
+        case ADD_REGION_SAMPLING_LISTENER:
+        case REMOVE_REGION_SAMPLING_LISTENER: {
             // codes that require permission check
             IPCThreadState* ipc = IPCThreadState::self();
             const int pid = ipc->getCallingPid();
@@ -5186,7 +5129,7 @@
             case 1016: {
                 n = data.readInt32();
                 // TODO(b/113612090): Evaluate if this can be removed.
-                mPrimaryDispSync->setRefreshSkipCount(n);
+                mScheduler->setRefreshSkipCount(n);
                 return NO_ERROR;
             }
             case 1017: {
@@ -5196,20 +5139,12 @@
             }
             case 1018: { // Modify Choreographer's phase offset
                 n = data.readInt32();
-                if (mUseScheduler) {
-                    mScheduler->setPhaseOffset(mAppConnectionHandle, static_cast<nsecs_t>(n));
-                } else {
-                    mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
-                }
+                mScheduler->setPhaseOffset(mAppConnectionHandle, static_cast<nsecs_t>(n));
                 return NO_ERROR;
             }
             case 1019: { // Modify SurfaceFlinger's phase offset
                 n = data.readInt32();
-                if (mUseScheduler) {
-                    mScheduler->setPhaseOffset(mSfConnectionHandle, static_cast<nsecs_t>(n));
-                } else {
-                    mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
-                }
+                mScheduler->setPhaseOffset(mSfConnectionHandle, static_cast<nsecs_t>(n));
                 return NO_ERROR;
             }
             case 1020: { // Layer updates interceptor
@@ -5390,8 +5325,8 @@
     DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace,
                                  renderAreaRotation);
 
-    auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
-                                    display, std::placeholders::_1);
+    auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display,
+                                    std::placeholders::_1);
     return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat,
                                useIdentityTransform);
 }
@@ -5426,6 +5361,7 @@
         }
         bool isSecure() const override { return false; }
         bool needsFiltering() const override { return mNeedsFiltering; }
+        const sp<const DisplayDevice> getDisplayDevice() const override { return nullptr; }
         Rect getSourceCrop() const override {
             if (mCrop.isEmpty()) {
                 return getBounds();
@@ -5438,8 +5374,11 @@
             const sp<Layer>& oldParent;
             const sp<Layer>& newParent;
 
-            ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent)
+            ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent,
+                               const Rect& drawingBounds)
                   : oldParent(oldParent), newParent(newParent) {
+                // Compute and cache the bounds for the new parent layer.
+                newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform());
                 oldParent->setChildrenDrawingParent(newParent);
             }
             ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
@@ -5460,7 +5399,7 @@
                         LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
                                           bounds.getWidth(), bounds.getHeight(), 0));
 
-                ReparentForDrawing reparent(mLayer, screenshotParentLayer);
+                ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
                 drawLayers();
             }
         }
@@ -5546,6 +5485,13 @@
                                              static_cast<android_pixel_format>(reqPixelFormat), 1,
                                              usage, "screenshot");
 
+    return captureScreenCore(renderArea, traverseLayers, *outBuffer, useIdentityTransform);
+}
+
+status_t SurfaceFlinger::captureScreenCore(RenderArea& renderArea,
+                                           TraverseLayersFunction traverseLayers,
+                                           const sp<GraphicBuffer>& buffer,
+                                           bool useIdentityTransform) {
     // This mutex protects syncFd and captureResult for communication of the return values from the
     // main thread back to this Binder thread
     std::mutex captureMutex;
@@ -5573,7 +5519,7 @@
         {
             Mutex::Autolock _l(mStateLock);
             renderArea.render([&] {
-                result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
+                result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
                                                  useIdentityTransform, forSystem, &fd);
             });
         }
@@ -5610,35 +5556,112 @@
 
 void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
                                             TraverseLayersFunction traverseLayers,
-                                            bool useIdentityTransform) {
+                                            ANativeWindowBuffer* buffer, bool useIdentityTransform,
+                                            int* outSyncFd) {
     ATRACE_CALL();
 
-    auto& engine(getRenderEngine());
-
     const auto reqWidth = renderArea.getReqWidth();
     const auto reqHeight = renderArea.getReqHeight();
     const auto sourceCrop = renderArea.getSourceCrop();
     const auto rotation = renderArea.getRotationFlags();
 
-    engine.setOutputDataSpace(renderArea.getReqDataSpace());
-    engine.setDisplayMaxLuminance(DisplayDevice::sDefaultMaxLumiance);
+    renderengine::DisplaySettings clientCompositionDisplay;
+    std::vector<renderengine::LayerSettings> clientCompositionLayers;
 
-    // make sure to clear all GL error flags
-    engine.checkErrors();
+    // assume that bounds are never offset, and that they are the same as the
+    // buffer bounds.
+    clientCompositionDisplay.physicalDisplay = Rect(reqWidth, reqHeight);
+    ui::Transform transform = renderArea.getTransform();
+    mat4 m;
+    m[0][0] = transform[0][0];
+    m[0][1] = transform[0][1];
+    m[0][3] = transform[0][2];
+    m[1][0] = transform[1][0];
+    m[1][1] = transform[1][1];
+    m[1][3] = transform[1][2];
+    m[3][0] = transform[2][0];
+    m[3][1] = transform[2][1];
+    m[3][3] = transform[2][2];
 
-    // set-up our viewport
-    engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, rotation);
-    engine.disableTexturing();
+    clientCompositionDisplay.globalTransform = m;
+    mat4 rotMatrix;
+    // Displacement for repositioning the clipping rectangle after rotating it
+    // with the rotation hint.
+    int displacementX = 0;
+    int displacementY = 0;
+    float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
+    switch (rotation) {
+        case ui::Transform::ROT_90:
+            rotMatrix = mat4::rotate(rot90InRadians, vec3(0, 0, 1));
+            displacementX = reqWidth;
+            break;
+        case ui::Transform::ROT_180:
+            rotMatrix = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1));
+            displacementX = reqWidth;
+            displacementY = reqHeight;
+            break;
+        case ui::Transform::ROT_270:
+            rotMatrix = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1));
+            displacementY = reqHeight;
+            break;
+        default:
+            break;
+    }
+    // We need to transform the clipping window into the right spot.
+    // First, rotate the clipping rectangle by the rotation hint to get the
+    // right orientation
+    const vec4 clipTL = vec4(sourceCrop.left, sourceCrop.top, 0, 1);
+    const vec4 clipBR = vec4(sourceCrop.right, sourceCrop.bottom, 0, 1);
+    const vec4 rotClipTL = rotMatrix * clipTL;
+    const vec4 rotClipBR = rotMatrix * clipBR;
+    const int newClipLeft = std::min(rotClipTL[0], rotClipBR[0]);
+    const int newClipTop = std::min(rotClipTL[1], rotClipBR[1]);
+    const int newClipRight = std::max(rotClipTL[0], rotClipBR[0]);
+    const int newClipBottom = std::max(rotClipTL[1], rotClipBR[1]);
+
+    // Now reposition the clipping rectangle with the displacement vector
+    // computed above.
+    const mat4 displacementMat = mat4::translate(vec4(displacementX, displacementY, 0, 1));
+
+    clientCompositionDisplay.clip =
+            Rect(newClipLeft + displacementX, newClipTop + displacementY,
+                 newClipRight + displacementX, newClipBottom + displacementY);
+
+    // We need to perform the same transformation in layer space, so propagate
+    // it to the global transform.
+    mat4 clipTransform = displacementMat * rotMatrix;
+    clientCompositionDisplay.globalTransform *= clipTransform;
+    clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace();
+    clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance;
 
     const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
-    // redraw the screen entirely...
-    engine.clearWithColor(0, 0, 0, alpha);
 
+    renderengine::LayerSettings fillLayer;
+    fillLayer.source.buffer.buffer = nullptr;
+    fillLayer.source.solidColor = half3(0.0, 0.0, 0.0);
+    fillLayer.geometry.boundaries = FloatRect(0.0, 0.0, 1.0, 1.0);
+    fillLayer.alpha = half(alpha);
+    clientCompositionLayers.push_back(fillLayer);
+
+    Region clearRegion = Region::INVALID_REGION;
     traverseLayers([&](Layer* layer) {
-        engine.setColorTransform(layer->getColorTransform());
-        layer->draw(renderArea, useIdentityTransform);
-        engine.setColorTransform(mat4());
+        renderengine::LayerSettings layerSettings;
+        bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion,
+                                                  layerSettings);
+        if (prepared) {
+            clientCompositionLayers.push_back(layerSettings);
+        }
     });
+
+    clientCompositionDisplay.clearRegion = clearRegion;
+    // Use an empty fence for the buffer fence, since we just created the buffer so
+    // there is no need for synchronization with the GPU.
+    base::unique_fd bufferFence;
+    base::unique_fd drawFence;
+    getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer,
+                                 std::move(bufferFence), &drawFence);
+
+    *outSyncFd = drawFence.release();
 }
 
 status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
@@ -5662,31 +5685,17 @@
         ALOGW("FB is protected: PERMISSION_DENIED");
         return PERMISSION_DENIED;
     }
-    auto& engine(getRenderEngine());
-
-    // this binds the given EGLImage as a framebuffer for the
-    // duration of this scope.
-    renderengine::BindNativeBufferAsFramebuffer bufferBond(engine, buffer);
-    if (bufferBond.getStatus() != NO_ERROR) {
-        ALOGE("got ANWB binding error while taking screenshot");
-        return INVALID_OPERATION;
-    }
-
-    // this will in fact render into our dequeued buffer
-    // via an FBO, which means we didn't have to create
-    // an EGLSurface and therefore we're not
-    // dependent on the context's EGLConfig.
-    renderScreenImplLocked(renderArea, traverseLayers, useIdentityTransform);
-
-    base::unique_fd syncFd = engine.flush();
-    if (syncFd < 0) {
-        engine.finish();
-    }
-    *outSyncFd = syncFd.release();
-
+    renderScreenImplLocked(renderArea, traverseLayers, buffer, useIdentityTransform, outSyncFd);
     return NO_ERROR;
 }
 
+void SurfaceFlinger::setInputWindowsFinished() {
+    Mutex::Autolock _l(mStateLock);
+
+    mPendingSyncInputWindows = false;
+    mTransactionCV.broadcast();
+}
+
 // ---------------------------------------------------------------------------
 
 void SurfaceFlinger::State::traverseInZOrder(const LayerVector::Visitor& visitor) const {
@@ -5718,6 +5727,12 @@
     }
 }
 
+// ----------------------------------------------------------------------------
+
+void SetInputWindowsListener::onSetInputWindowsFinished() {
+    mFlinger->setInputWindowsFinished();
+}
+
 }; // namespace android
 
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a127550..31b4fb6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -33,6 +33,7 @@
 #include <gui/LayerState.h>
 #include <gui/OccupancyTracker.h>
 #include <hardware/hwcomposer_defs.h>
+#include <input/ISetInputWindowsListener.h>
 #include <layerproto/LayerProtoHeader.h>
 #include <math/mat4.h>
 #include <serviceutils/PriorityDumper.h>
@@ -56,10 +57,12 @@
 #include "LayerBE.h"
 #include "LayerStats.h"
 #include "LayerVector.h"
+#include "RegionSamplingThread.h"
 #include "Scheduler/DispSync.h"
 #include "Scheduler/EventThread.h"
 #include "Scheduler/MessageQueue.h"
 #include "Scheduler/PhaseOffsets.h"
+#include "Scheduler/RefreshRateConfigs.h"
 #include "Scheduler/RefreshRateStats.h"
 #include "Scheduler/Scheduler.h"
 #include "Scheduler/VSyncModulator.h"
@@ -168,9 +171,6 @@
     nsecs_t mTotalTime;
     std::atomic<nsecs_t> mLastSwapTime;
 
-    // Synchronization fence from a GL composition.
-    sp<Fence> flushFence = Fence::NO_FENCE;
-
     // Double- vs. triple-buffering stats
     struct BufferingStats {
         BufferingStats()
@@ -203,6 +203,14 @@
     std::map<wp<IBinder>, std::vector<CompositionInfo>> mEndOfFrameCompositionInfo;
 };
 
+class SetInputWindowsListener : public BnSetInputWindowsListener {
+public:
+    SetInputWindowsListener(const sp<SurfaceFlinger>& flinger) : mFlinger(flinger) {}
+    void onSetInputWindowsFinished() override;
+
+private:
+    const sp<SurfaceFlinger> mFlinger;
+};
 
 class SurfaceFlinger : public BnSurfaceComposer,
                        public PriorityDumper,
@@ -313,7 +321,7 @@
     compositionengine::CompositionEngine& getCompositionEngine() const;
 
     // returns the default Display
-    sp<const DisplayDevice> getDefaultDisplayDevice() const {
+    sp<const DisplayDevice> getDefaultDisplayDevice() {
         Mutex::Autolock _l(mStateLock);
         return getDefaultDisplayDeviceLocked();
     }
@@ -327,7 +335,7 @@
 
     // enable/disable h/w composer event
     // TODO: this should be made accessible only to EventThread
-    void setVsyncEnabled(EventThread::DisplayType displayType, bool enabled);
+    void setPrimaryVsyncEnabled(bool enabled);
 
     // called on the main thread by MessageQueue when an internal message
     // is received
@@ -350,6 +358,8 @@
         return mTransactionCompletedThread;
     }
 
+    void setInputWindowsFinished();
+
 private:
     friend class Client;
     friend class DisplayEventConnection;
@@ -359,6 +369,7 @@
     friend class BufferQueueLayer;
     friend class BufferStateLayer;
     friend class MonitoredProducer;
+    friend class RegionSamplingThread;
 
     // For unit tests
     friend class TestableSurfaceFlinger;
@@ -407,6 +418,7 @@
      */
     status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
     status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); }
+    bool callingThreadHasUnscopedSurfaceFlingerAccess() EXCLUDES(mStateLock);
 
     /* ------------------------------------------------------------------------
      * ISurfaceComposer interface
@@ -414,7 +426,8 @@
     sp<ISurfaceComposerClient> createConnection() override;
     sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
     void destroyDisplay(const sp<IBinder>& displayToken) override;
-    sp<IBinder> getBuiltInDisplay(int32_t id) override;
+    std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override;
+    sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
     void setTransactionState(const Vector<ComposerState>& state,
                              const Vector<DisplayState>& displays, uint32_t flags,
                              const sp<IBinder>& applyToken,
@@ -435,7 +448,12 @@
                            const Rect& sourceCrop, float frameScale, bool childrenOnly) override;
     status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
     status_t getDisplayConfigs(const sp<IBinder>& displayToken,
-                               Vector<DisplayInfo>* configs) override;
+                               Vector<DisplayInfo>* configs) override {
+        Mutex::Autolock _l(mStateLock);
+        return getDisplayConfigsLocked(displayToken, configs);
+    }
+    status_t getDisplayConfigsLocked(const sp<IBinder>& displayToken, Vector<DisplayInfo>* configs)
+            REQUIRES(mStateLock);
     int getActiveConfig(const sp<IBinder>& displayToken) override;
     status_t getDisplayColorModes(const sp<IBinder>& displayToken,
                                   Vector<ui::ColorMode>* configs) override;
@@ -469,7 +487,9 @@
     status_t getProtectedContentSupport(bool* outSupported) const override;
     status_t isWideColorDisplay(const sp<IBinder>& displayToken,
                                 bool* outIsWideColorDisplay) const override;
-
+    status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+                                       const sp<IRegionSamplingListener>& listener) override;
+    status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
     /* ------------------------------------------------------------------------
      * DeathRecipient interface
      */
@@ -501,10 +521,16 @@
 
     // called on the main thread in response to initializeDisplays()
     void onInitializeDisplays() REQUIRES(mStateLock);
-    // setActiveConfigInternal() posted on a main thread for async execution
-    status_t setActiveConfigAsync(const sp<IBinder>& displayToken, int mode);
-    // called on the main thread in response to setActiveConfig()
-    void setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock);
+    // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
+    void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock);
+    // Once HWC has returned the present fence, this sets the active config and a new refresh
+    // rate in SF. It also triggers HWC vsync.
+    void setActiveConfigInternal() REQUIRES(mStateLock);
+    // Active config is updated on INVALIDATE call in a state machine-like manner. When the
+    // desired config was set, HWC needs to update the panel on the next refresh, and when
+    // we receive the fence back, we know that the process was complete. It returns whether
+    // we need to wait for the next invalidate
+    bool performSetActiveConfig();
     // called on the main thread in response to setPowerMode()
     void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
 
@@ -517,9 +543,11 @@
     void handleMessageRefresh();
 
     void handleTransaction(uint32_t transactionFlags);
-    void handleTransactionLocked(uint32_t transactionFlags);
+    void handleTransactionLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
 
-    void updateInputWindows();
+    void updateInputFlinger();
+    void updateInputWindowInfo();
+    void commitInputWindowCommands() REQUIRES(mStateLock);
     void executeInputWindowCommands();
     void updateCursorAsync();
 
@@ -534,7 +562,8 @@
      */
     void applyTransactionState(const Vector<ComposerState>& state,
                                const Vector<DisplayState>& displays, uint32_t flags,
-                               const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock);
+                               const InputWindowCommands& inputWindowCommands,
+                               bool privileged) REQUIRES(mStateLock);
     bool flushTransactionQueues();
     uint32_t getTransactionFlags(uint32_t flags);
     uint32_t peekTransactionFlags();
@@ -546,9 +575,10 @@
     bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
     bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
                                        const Vector<ComposerState>& states);
-    uint32_t setClientStateLocked(const ComposerState& composerState);
+    uint32_t setClientStateLocked(const ComposerState& composerState, bool privileged);
     uint32_t setDisplayStateLocked(const DisplayState& s);
-    uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands);
+    uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
+            REQUIRES(mStateLock);
 
     /* ------------------------------------------------------------------------
      * Layer management
@@ -590,6 +620,9 @@
             const sp<Layer>& parent,
             bool addToCurrentState);
 
+    // Traverse through all the layers and compute and cache its bounds.
+    void computeLayerBounds();
+
     /* ------------------------------------------------------------------------
      * Boot animation, on/off animations and screen capture
      */
@@ -597,10 +630,13 @@
     void startBootAnim();
 
     void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
-                                bool useIdentityTransform);
+                                ANativeWindowBuffer* buffer, bool useIdentityTransform,
+                                int* outSyncFd);
     status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
                                  sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
                                  bool useIdentityTransform);
+    status_t captureScreenCore(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+                               const sp<GraphicBuffer>& buffer, bool useIdentityTransform);
     status_t captureScreenImplLocked(const RenderArea& renderArea,
                                      TraverseLayersFunction traverseLayers,
                                      ANativeWindowBuffer* buffer, bool useIdentityTransform,
@@ -653,7 +689,7 @@
     }
 
     sp<DisplayDevice> getDefaultDisplayDeviceLocked() {
-        if (const auto token = getInternalDisplayToken()) {
+        if (const auto token = getInternalDisplayTokenLocked()) {
             return getDisplayDeviceLocked(token);
         }
         return nullptr;
@@ -736,8 +772,11 @@
     void logLayerStats();
     void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion);
 
-    // This fails if using GL and the surface has been destroyed.
-    bool doComposeSurfaces(const sp<DisplayDevice>& display);
+    // 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 postFramebuffer(const sp<DisplayDevice>& display);
     void postFrame();
@@ -754,52 +793,26 @@
     void processDisplayChangesLocked();
     void processDisplayHotplugEventsLocked();
 
-    void dispatchDisplayHotplugEvent(EventThread::DisplayType displayType, bool connected);
+    void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
 
     /* ------------------------------------------------------------------------
      * VSync
      */
     nsecs_t getVsyncPeriod() const REQUIRES(mStateLock);
-    void enableHardwareVsync();
-    void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
-    void disableHardwareVsync(bool makeUnavailable);
 
-    // Sets the refresh rate to newFps by switching active configs, if they are available for
+    // Sets the refresh rate by switching active configs, if they are available for
     // the desired refresh rate.
-    void setRefreshRateTo(float newFps);
-
-    using GetVsyncPeriod = std::function<nsecs_t()>;
-
-    // Stores per-display state about VSYNC.
-    struct VsyncState {
-        explicit VsyncState(SurfaceFlinger& flinger) : flinger(flinger) {}
-
-        void resync(const GetVsyncPeriod&);
-
-        SurfaceFlinger& flinger;
-        std::atomic<nsecs_t> lastResyncTime = 0;
-    };
-
-    const std::shared_ptr<VsyncState> mPrimaryVsyncState{std::make_shared<VsyncState>(*this)};
-
-    auto makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
-        std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
-        return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
-            if (const auto vsync = ptr.lock()) {
-                vsync->resync(getVsyncPeriod);
-            }
-        };
-    }
+    void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType) REQUIRES(mStateLock);
 
     /*
      * Display identification
      */
-    sp<IBinder> getPhysicalDisplayToken(DisplayId displayId) const {
+    sp<IBinder> getPhysicalDisplayTokenLocked(DisplayId displayId) const {
         const auto it = mPhysicalDisplayTokens.find(displayId);
         return it != mPhysicalDisplayTokens.end() ? it->second : nullptr;
     }
 
-    std::optional<DisplayId> getPhysicalDisplayId(const sp<IBinder>& displayToken) const {
+    std::optional<DisplayId> getPhysicalDisplayIdLocked(const sp<IBinder>& displayToken) const {
         for (const auto& [id, token] : mPhysicalDisplayTokens) {
             if (token == displayToken) {
                 return id;
@@ -809,22 +822,16 @@
     }
 
     // TODO(b/74619554): Remove special cases for primary display.
-    sp<IBinder> getInternalDisplayToken() const {
-        const auto displayId = getInternalDisplayId();
-        return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+    sp<IBinder> getInternalDisplayTokenLocked() const {
+        const auto displayId = getInternalDisplayIdLocked();
+        return displayId ? getPhysicalDisplayTokenLocked(*displayId) : nullptr;
     }
 
-    std::optional<DisplayId> getInternalDisplayId() const {
+    std::optional<DisplayId> getInternalDisplayIdLocked() const {
         const auto hwcDisplayId = getHwComposer().getInternalHwcDisplayId();
         return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
     }
 
-    // TODO(b/74619554): Remove special cases for external display.
-    std::optional<DisplayId> getExternalDisplayId() const {
-        const auto hwcDisplayId = getHwComposer().getExternalHwcDisplayId();
-        return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
-    }
-
     /*
      * Debugging & dumpsys
      */
@@ -874,9 +881,8 @@
     void dumpBufferingStats(std::string& result) const;
     void dumpDisplayIdentificationData(std::string& result) const;
     void dumpWideColorInfo(std::string& result) const;
-    void dumpFrameCompositionInfo(std::string& result) const;
     LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
-    LayersProto dumpVisibleLayersProtoInfo(const DisplayDevice& display) const;
+    LayersProto dumpVisibleLayersProtoInfo(const sp<DisplayDevice>& display) const;
 
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
@@ -935,14 +941,9 @@
     // constant members (no synchronization needed for access)
     nsecs_t mBootTime;
     bool mGpuToCpuSupported;
-    std::unique_ptr<EventThread> mEventThread;
-    std::unique_ptr<EventThread> mSFEventThread;
     std::unique_ptr<EventThread> mInjectorEventThread;
-    std::unique_ptr<VSyncSource> mEventThreadSource;
-    std::unique_ptr<VSyncSource> mSfEventThreadSource;
     std::unique_ptr<InjectVSyncSource> mVSyncInjector;
     std::unique_ptr<EventControlThread> mEventControlThread;
-    std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
 
     // Calculates correct offsets.
     VSyncModulator mVsyncModulator;
@@ -953,9 +954,13 @@
     // don't need synchronization
     State mDrawingState{LayerVector::StateSet::Drawing};
     bool mVisibleRegionsDirty;
+    // Set during transaction commit stage to track if the input info for a layer has changed.
+    bool mInputInfoChanged{false};
     bool mGeometryInvalid;
     bool mAnimCompositionPending;
     std::vector<sp<Layer>> mLayersWithQueuedFrames;
+    // Tracks layers that need to update a display's dirty region.
+    std::vector<sp<Layer>> mLayersPendingRefresh;
     sp<Fence> mPreviousPresentFence = Fence::NO_FENCE;
     bool mHadClientComposition = false;
 
@@ -976,6 +981,7 @@
     // this may only be written from the main thread with mStateLock held
     // it may be read from other threads with mStateLock held
     std::map<wp<IBinder>, sp<DisplayDevice>> mDisplays;
+    std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
 
     // don't use a lock for these, we don't care
     int mDebugRegion;
@@ -996,22 +1002,20 @@
 
     TransactionCompletedThread mTransactionCompletedThread;
 
+    bool mLumaSampling = true;
+    sp<RegionSamplingThread> mRegionSamplingThread = new RegionSamplingThread(*this);
+
     // Restrict layers to use two buffers in their bufferqueues.
     bool mLayerTripleBufferingDisabled = false;
 
     // these are thread safe
     mutable std::unique_ptr<MessageQueue> mEventQueue{mFactory.createMessageQueue()};
     FrameTracker mAnimFrameTracker;
-    std::unique_ptr<DispSync> mPrimaryDispSync;
 
     // protected by mDestroyedLayerLock;
     mutable Mutex mDestroyedLayerLock;
     Vector<Layer const *> mDestroyedLayers;
 
-    // protected by mHWVsyncLock
-    Mutex mHWVsyncLock;
-    bool mPrimaryHWVsyncEnabled;
-    bool mHWVsyncAvailable;
     nsecs_t mRefreshStartTime;
 
     std::atomic<bool> mRefreshPending{false};
@@ -1031,16 +1035,19 @@
     struct TransactionState {
         TransactionState(const Vector<ComposerState>& composerStates,
                          const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
-                         int64_t desiredPresentTime)
+                         int64_t desiredPresentTime,
+                         bool privileged)
               : states(composerStates),
                 displays(displayStates),
                 flags(transactionFlags),
-                time(desiredPresentTime) {}
+                time(desiredPresentTime),
+                privileged(privileged) {}
 
         Vector<ComposerState> states;
         Vector<DisplayState> displays;
         uint32_t flags;
         int64_t time;
+        bool privileged;
     };
     std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IBinderHash> mTransactionQueues;
 
@@ -1066,6 +1073,15 @@
 
     DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::ENHANCED;
 
+    // Color mode forced by setting persist.sys.sf.color_mode, it must:
+    //     1. not be NATIVE color mode, NATIVE color mode means no forced color mode;
+    //     2. be one of the supported color modes returned by hardware composer, otherwise
+    //        it will not be respected.
+    // persist.sys.sf.color_mode will only take effect when persist.sys.sf.native_mode
+    // is not set to 1.
+    // This property can be used to force SurfaceFlinger to always pick a certain color mode.
+    ui::ColorMode mForceColorMode = ui::ColorMode::NATIVE;
+
     ui::Dataspace mDefaultCompositionDataspace;
     ui::Dataspace mWideColorGamutCompositionDataspace;
 
@@ -1075,18 +1091,48 @@
     /* ------------------------------------------------------------------------
      * Scheduler
      */
-    bool mUseScheduler = false;
+    bool mUse90Hz = false;
+    bool mUseSmart90ForVideo = false;
     std::unique_ptr<Scheduler> mScheduler;
     sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
     sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
     std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
 
+    struct ActiveConfigInfo {
+        int configId;
+        sp<IBinder> displayToken;
+
+        bool operator!=(const ActiveConfigInfo& other) const {
+            if (configId != other.configId) {
+                return true;
+            }
+            return (displayToken != other.displayToken);
+        }
+    };
+    std::mutex mActiveConfigLock;
+    // This bit is set once we start setting the config. We read from this bit during the
+    // process. If at the end, this bit is different than mDesiredActiveConfig, we restart
+    // the process.
+    ActiveConfigInfo mUpcomingActiveConfig; // Always read and written on the main thread.
+    // This bit can be set at any point in time when the system wants the new config.
+    ActiveConfigInfo mDesiredActiveConfig GUARDED_BY(mActiveConfigLock);
+
+    // below flags are set by main thread only
+    bool mDesiredActiveConfigChanged GUARDED_BY(mActiveConfigLock) = false;
+    bool mWaitForNextInvalidate = false;
+    bool mCheckPendingFence = false;
+
     /* ------------------------------------------------------------------------ */
     sp<IInputFlinger> mInputFlinger;
 
+    InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
+    // Should only be accessed by the main thread.
     InputWindowCommands mInputWindowCommands;
 
     ui::DisplayPrimaries mInternalDisplayPrimaries;
+
+    sp<SetInputWindowsListener> mSetInputWindowsListener;
+    bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
 };
 }; // namespace android
 
diff --git a/services/surfaceflinger/TimeStats/OWNERS b/services/surfaceflinger/TimeStats/OWNERS
new file mode 100644
index 0000000..ac02d12
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/OWNERS
@@ -0,0 +1 @@
+zzyiwei@google.com
\ No newline at end of file
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index 5c72fea..7ab57f9 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -199,13 +199,13 @@
         }
     }
 
-    if (layerProto.has_parent()) {
+    if (layerProto.parent() != -1) {
         if (layerMap.count(layerProto.parent()) > 0) {
             currLayer->parent = layerMap[layerProto.parent()];
         }
     }
 
-    if (layerProto.has_z_order_relative_of()) {
+    if (layerProto.z_order_relative_of() != -1) {
         if (layerMap.count(layerProto.z_order_relative_of()) > 0) {
             currLayer->zOrderRelativeOf = layerMap[layerProto.z_order_relative_of()];
         }
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 4c756d9..faf0c54 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -1,151 +1,156 @@
 // Definitions for SurfaceFlinger layers.
 
-syntax = "proto2";
+syntax = "proto3";
 option optimize_for = LITE_RUNTIME;
 package android.surfaceflinger;
 
 // Contains a list of all layers.
 message LayersProto {
   repeated LayerProto layers = 1;
-  optional SizeProto resolution = 2;
-  optional string color_mode = 3;
-  optional string color_transform = 4;
-  optional int32 global_transform = 5;
+  SizeProto resolution = 2;
+  string color_mode = 3;
+  string color_transform = 4;
+  int32 global_transform = 5;
 }
 
 // Information about each layer.
 message LayerProto {
   // unique id per layer.
-  optional int32 id = 1;
+  int32 id = 1;
   // unique name per layer.
-  optional string name = 2;
+  string name = 2;
   // list of children this layer may have. May be empty.
   repeated int32 children = 3;
   // list of layers that are z order relative to this layer.
   repeated int32 relatives = 4;
   // The type of layer, ex Color, Layer
-  optional string type = 5;
-  optional RegionProto transparent_region = 6;
-  optional RegionProto visible_region = 7;
-  optional RegionProto damage_region = 8;
-  optional uint32 layer_stack = 9;
+  string type = 5;
+  RegionProto transparent_region = 6;
+  RegionProto visible_region = 7;
+  RegionProto damage_region = 8;
+  uint32 layer_stack = 9;
   // The layer's z order. Can be z order in layer stack, relative to parent,
   // or relative to another layer specified in zOrderRelative.
-  optional int32 z = 10;
+  int32 z = 10;
   // The layer's position on the display.
-  optional PositionProto position = 11;
+  PositionProto position = 11;
   // The layer's requested position.
-  optional PositionProto requested_position = 12;
+  PositionProto requested_position = 12;
   // The layer's size.
-  optional SizeProto size = 13;
+  SizeProto size = 13;
   // The layer's crop in it's own bounds.
-  optional RectProto crop = 14;
+  RectProto crop = 14;
   // The layer's crop in it's parent's bounds.
-  optional RectProto final_crop = 15 [deprecated=true];
-  optional bool is_opaque = 16;
-  optional bool invalidate = 17;
-  optional string dataspace = 18;
-  optional string pixel_format = 19;
+  RectProto final_crop = 15 [deprecated=true];
+  bool is_opaque = 16;
+  bool invalidate = 17;
+  string dataspace = 18;
+  string pixel_format = 19;
   // The layer's actual color.
-  optional ColorProto color = 20;
+  ColorProto color = 20;
   // The layer's requested color.
-  optional ColorProto requested_color = 21;
+  ColorProto requested_color = 21;
   // Can be any combination of
   //    hidden = 0x01
   //    opaque = 0x02,
   //    secure = 0x80,
-  optional uint32 flags = 22;
+  uint32 flags = 22;
   // The layer's actual transform
-  optional TransformProto transform = 23;
+  TransformProto transform = 23;
   // The layer's requested transform.
-  optional TransformProto requested_transform = 24;
+  TransformProto requested_transform = 24;
   // The parent layer. This value can be null if there is no parent.
-  optional int32 parent = 25 [default = -1];
+  int32 parent = 25;
   // The layer that this layer has a z order relative to. This value can be null.
-  optional int32 z_order_relative_of = 26 [default = -1];
+  int32 z_order_relative_of = 26;
   // This value can be null if there's nothing to draw.
-  optional ActiveBufferProto active_buffer = 27;
+  ActiveBufferProto active_buffer = 27;
   // The number of frames available.
-  optional int32 queued_frames = 28;
-  optional bool refresh_pending = 29;
+  int32 queued_frames = 28;
+  bool refresh_pending = 29;
   // The layer's composer backend destination frame
-  optional RectProto hwc_frame = 30;
+  RectProto hwc_frame = 30;
   // The layer's composer backend source crop
-  optional FloatRectProto hwc_crop = 31;
+  FloatRectProto hwc_crop = 31;
   // The layer's composer backend transform
-  optional int32 hwc_transform = 32;
-  optional int32 window_type = 33 [deprecated=true];
-  optional int32 app_id = 34 [deprecated=true];
+  int32 hwc_transform = 32;
+  int32 window_type = 33 [deprecated=true];
+  int32 app_id = 34 [deprecated=true];
   // The layer's composition type
-  optional int32 hwc_composition_type = 35;
+  int32 hwc_composition_type = 35;
   // If it's a buffer layer, indicate if the content is protected
-  optional bool is_protected = 36;
+  bool is_protected = 36;
   // Current frame number being rendered.
-  optional uint64 curr_frame = 37;
+  uint64 curr_frame = 37;
   // A list of barriers that the layer is waiting to update state.
   repeated BarrierLayerProto barrier_layer = 38;
   // If active_buffer is not null, record its transform.
-  optional TransformProto buffer_transform = 39;
-  optional int32 effective_scaling_mode = 40;
+  TransformProto buffer_transform = 39;
+  int32 effective_scaling_mode = 40;
   // Layer's corner radius.
-  optional float corner_radius = 41;
+  float corner_radius = 41;
   // Metadata map. May be empty.
   map<int32, bytes> metadata = 42;
+
+  TransformProto effective_transform = 43;
+  FloatRectProto source_bounds = 44;
+  FloatRectProto bounds = 45;
+  FloatRectProto screen_bounds = 46;
 }
 
 message PositionProto {
-  optional float x = 1;
-  optional float y = 2;
+  float x = 1;
+  float y = 2;
 }
 
 message SizeProto {
-  optional int32 w = 1;
-  optional int32 h = 2;
+  int32 w = 1;
+  int32 h = 2;
 }
 
 message TransformProto {
-  optional float dsdx = 1;
-  optional float dtdx = 2;
-  optional float dsdy = 3;
-  optional float dtdy = 4;
+  float dsdx = 1;
+  float dtdx = 2;
+  float dsdy = 3;
+  float dtdy = 4;
 }
 
 message RegionProto {
-  optional uint64 id = 1;
+  uint64 id = 1;
   repeated RectProto rect = 2;
 }
 
 message RectProto {
-  optional int32 left   = 1;
-  optional int32 top    = 2;
-  optional int32 right  = 3;
-  optional int32 bottom = 4;
+  int32 left   = 1;
+  int32 top    = 2;
+  int32 right  = 3;
+  int32 bottom = 4;
 }
 
 message FloatRectProto {
-  optional float left = 1;
-  optional float top = 2;
-  optional float right = 3;
-  optional float bottom = 4;
+  float left = 1;
+  float top = 2;
+  float right = 3;
+  float bottom = 4;
 }
 
 message ActiveBufferProto {
-  optional uint32 width = 1;
-  optional uint32 height = 2;
-  optional uint32 stride = 3;
-  optional int32 format = 4;
+  uint32 width = 1;
+  uint32 height = 2;
+  uint32 stride = 3;
+  int32 format = 4;
 }
 
 message ColorProto {
-  optional float r = 1;
-  optional float g = 2;
-  optional float b = 3;
-  optional float a = 4;
+  float r = 1;
+  float g = 2;
+  float b = 3;
+  float a = 4;
 }
 
 message BarrierLayerProto {
   // layer id the barrier is waiting on.
-  optional int32 id = 1;
+  int32 id = 1;
   // frame number the barrier is waiting on.
-  optional uint64 frame_number = 2;
+  uint64 frame_number = 2;
 }
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index 5bec502..aea602b 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -2,7 +2,6 @@
     class core animation
     user system
     group graphics drmrpc readproc
-    updatable
     onrestart restart zygote
     writepid /dev/stune/foreground/tasks
     socket pdx/system/vr/display/client     stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index f021d3d..61d09da 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -62,9 +62,11 @@
     }
 
     void setupBackgroundSurface() {
-        mDisplay = SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+        mDisplay = SurfaceComposerClient::getInternalDisplayToken();
+        ASSERT_FALSE(mDisplay == nullptr);
+
         DisplayInfo info;
-        SurfaceComposerClient::getDisplayInfo(mDisplay, &info);
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
         const ssize_t displayWidth = info.w;
         const ssize_t displayHeight = info.h;
 
@@ -170,10 +172,8 @@
 }
 
 TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) {
-    std::function<bool()> condition = [=]() {
-        sp<IBinder> display(
-                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-        return (display != nullptr);
+    std::function<bool()> condition = [] {
+        return SurfaceComposerClient::getInternalDisplayToken() != nullptr;
     };
     // Anyone can access display information.
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true));
@@ -183,7 +183,7 @@
     // The following methods are tested with a UID that is not root, graphics,
     // or system, to show that anyone can access them.
     setBinUID();
-    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    const auto display = SurfaceComposerClient::getInternalDisplayToken();
     ASSERT_TRUE(display != nullptr);
 
     DisplayInfo info;
@@ -199,7 +199,7 @@
 }
 
 TEST_F(CredentialsTest, GetDisplayColorModesTest) {
-    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    const auto display = SurfaceComposerClient::getInternalDisplayToken();
     std::function<status_t()> condition = [=]() {
         Vector<ui::ColorMode> outColorModes;
         return SurfaceComposerClient::getDisplayColorModes(display, &outColorModes);
@@ -208,7 +208,7 @@
 }
 
 TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) {
-    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    const auto display = SurfaceComposerClient::getInternalDisplayToken();
     std::function<status_t()> condition = [=]() {
         ui::DisplayPrimaries primaries;
         return SurfaceComposerClient::getDisplayNativePrimaries(display, primaries);
@@ -217,7 +217,7 @@
 }
 
 TEST_F(CredentialsTest, SetActiveConfigTest) {
-    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    const auto display = SurfaceComposerClient::getInternalDisplayToken();
     std::function<status_t()> condition = [=]() {
         return SurfaceComposerClient::setActiveConfig(display, 0);
     };
@@ -225,7 +225,7 @@
 }
 
 TEST_F(CredentialsTest, SetActiveColorModeTest) {
-    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    const auto display = SurfaceComposerClient::getInternalDisplayToken();
     std::function<status_t()> condition = [=]() {
         return SurfaceComposerClient::setActiveColorMode(display, ui::ColorMode::NATIVE);
     };
@@ -258,7 +258,7 @@
 }
 
 TEST_F(CredentialsTest, CaptureTest) {
-    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    const auto display = SurfaceComposerClient::getInternalDisplayToken();
     std::function<status_t()> condition = [=]() {
         sp<GraphicBuffer> outBuffer;
         return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB,
@@ -324,7 +324,8 @@
 }
 
 TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) {
-    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    const auto display = SurfaceComposerClient::getInternalDisplayToken();
+    ASSERT_FALSE(display == nullptr);
     bool result = false;
     status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result);
     ASSERT_EQ(NO_ERROR, error);
@@ -346,7 +347,8 @@
 }
 
 TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) {
-    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    const auto display = SurfaceComposerClient::getInternalDisplayToken();
+    ASSERT_FALSE(display == nullptr);
     std::function<status_t()> condition = [=]() {
         bool result = false;
         return SurfaceComposerClient::isWideColorDisplay(display, &result);
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index 89c26f4..ee857b0 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -34,7 +34,7 @@
             auto surf = client->createSurface(String8("t"), 100, 100,
                     PIXEL_FORMAT_RGBA_8888, 0);
             ASSERT_TRUE(surf != nullptr);
-            surf->clear();
+            surf.clear();
         }
     };
 
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 8ec3e15..5cc946a 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -240,10 +240,12 @@
 }
 
 void SurfaceInterceptorTest::setupBackgroundSurface() {
-    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
-                ISurfaceComposer::eDisplayIdMain));
+    const auto display = SurfaceComposerClient::getInternalDisplayToken();
+    ASSERT_FALSE(display == nullptr);
+
     DisplayInfo info;
-    SurfaceComposerClient::getDisplayInfo(display, &info);
+    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+
     ssize_t displayWidth = info.w;
     ssize_t displayHeight = info.h;
 
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index e631295..181dac6 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -195,13 +195,12 @@
 class ScreenCapture : public RefBase {
 public:
     static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+        const auto sf = ComposerService::getComposerService();
+        const auto token = sf->getInternalDisplayToken();
         SurfaceComposerClient::Transaction().apply(true);
 
         sp<GraphicBuffer> outBuffer;
-        ASSERT_EQ(NO_ERROR,
-                  sf->captureScreen(display, &outBuffer, Rect(), 0, 0, false));
+        ASSERT_EQ(NO_ERROR, sf->captureScreen(token, &outBuffer, Rect(), 0, 0, false));
         *sc = std::make_unique<ScreenCapture>(outBuffer);
     }
 
@@ -324,7 +323,6 @@
         ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
 
         sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        sp<IBinder> binder = sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
         ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
     }
 
@@ -502,12 +500,12 @@
 
 private:
     void SetUpDisplay() {
-        mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
-        ASSERT_NE(nullptr, mDisplay.get()) << "failed to get built-in display";
+        mDisplay = mClient->getInternalDisplayToken();
+        ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
 
         // get display width/height
         DisplayInfo info;
-        SurfaceComposerClient::getDisplayInfo(mDisplay, &info);
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
         mDisplayWidth = info.w;
         mDisplayHeight = info.h;
         mDisplayRect =
@@ -558,8 +556,7 @@
                 return mDelegate->screenshot();
             case RenderPath::VIRTUAL_DISPLAY:
 
-                sp<IBinder> mainDisplay =
-                        SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+                const auto mainDisplay = SurfaceComposerClient::getInternalDisplayToken();
                 DisplayInfo mainDisplayInfo;
                 SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo);
 
@@ -1137,7 +1134,7 @@
             .setRelativeLayer(layerG, layerR->getHandle(), 1)
             .apply();
 
-    layerG->clear();
+    layerG.clear();
     // layerG should have been removed
     getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
 }
@@ -1540,7 +1537,6 @@
         SCOPED_TRACE("default before setting background color layer");
         screenshot()->expectColor(Rect(0, 0, width, height), expectedColor);
     }
-
     Transaction()
             .setBackgroundColor(layer, half3(0, 1.0f, 0), alpha, ui::Dataspace::UNKNOWN)
             .apply();
@@ -1625,7 +1621,7 @@
     bool bufferFill = true;
     float alpha = 1.0f;
     Color finalColor = Color::RED;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
                                                      priorColor, bufferFill, alpha, finalColor));
 }
 
@@ -1635,7 +1631,7 @@
     bool bufferFill = false;
     float alpha = 1.0f;
     Color finalColor = Color::GREEN;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
                                                      priorColor, bufferFill, alpha, finalColor));
 }
 
@@ -1645,7 +1641,7 @@
     bool bufferFill = false;
     float alpha = 1.0f;
     Color finalColor = Color::GREEN;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
                                                      priorColor, bufferFill, alpha, finalColor));
 }
 
@@ -1655,7 +1651,7 @@
     bool bufferFill = false;
     float alpha = 0;
     Color finalColor = Color::BLACK;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
                                                      priorColor, bufferFill, alpha, finalColor));
 }
 
@@ -1665,7 +1661,7 @@
     bool bufferFill = false;
     float alpha = 0;
     Color finalColor = Color::BLACK;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
                                                      priorColor, bufferFill, alpha, finalColor));
 }
 
@@ -2405,7 +2401,7 @@
     }
 }
 
-TEST_F(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(
             layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2441,7 +2437,7 @@
     }
 }
 
-TEST_F(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(
             layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2477,7 +2473,7 @@
     }
 }
 
-TEST_F(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(
             layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -3129,16 +3125,25 @@
     }
 
     static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
-                               const sp<SurfaceControl>& layer = nullptr) {
+                               const sp<SurfaceControl>& layer = nullptr, bool setBuffer = true,
+                               bool setBackgroundColor = false) {
         if (layer) {
             sp<GraphicBuffer> buffer;
             sp<Fence> fence;
-            int err = getBuffer(&buffer, &fence);
-            if (err != NO_ERROR) {
-                return err;
+            if (setBuffer) {
+                int err = getBuffer(&buffer, &fence);
+                if (err != NO_ERROR) {
+                    return err;
+                }
+
+                transaction.setBuffer(layer, buffer);
+                transaction.setAcquireFence(layer, fence);
             }
 
-            transaction.setBuffer(layer, buffer).setAcquireFence(layer, fence);
+            if (setBackgroundColor) {
+                transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
+                                               ui::Dataspace::UNKNOWN);
+            }
         }
 
         transaction.addTransactionCompletedCallback(callbackHelper->function,
@@ -3169,13 +3174,13 @@
     }
 };
 
-TEST_F(LayerCallbackTest, Basic) {
+TEST_F(LayerCallbackTest, BufferColor) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
 
     Transaction transaction;
     CallbackHelper callback;
-    int err = fillTransaction(transaction, &callback, layer);
+    int err = fillTransaction(transaction, &callback, layer, true, true);
     if (err) {
         GTEST_SUCCEED() << "test not supported";
         return;
@@ -3188,13 +3193,13 @@
     EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
 }
 
-TEST_F(LayerCallbackTest, NoBuffer) {
+TEST_F(LayerCallbackTest, NoBufferNoColor) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
 
     Transaction transaction;
     CallbackHelper callback;
-    int err = fillTransaction(transaction, &callback);
+    int err = fillTransaction(transaction, &callback, layer, false, false);
     if (err) {
         GTEST_SUCCEED() << "test not supported";
         return;
@@ -3208,6 +3213,45 @@
     EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
 }
 
+TEST_F(LayerCallbackTest, BufferNoColor) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer, true, false);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoBufferColor) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer, false, true);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+                        ExpectedResult::Buffer::NOT_ACQUIRED);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
 TEST_F(LayerCallbackTest, NoStateChange) {
     Transaction transaction;
     CallbackHelper callback;
@@ -3242,7 +3286,7 @@
     EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
 }
 
-TEST_F(LayerCallbackTest, Merge) {
+TEST_F(LayerCallbackTest, MergeBufferNoColor) {
     sp<SurfaceControl> layer1, layer2;
     ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
     ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
@@ -3269,6 +3313,62 @@
     EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
 }
 
+TEST_F(LayerCallbackTest, MergeNoBufferColor) {
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    int err = fillTransaction(transaction1, &callback1, layer1, false, true);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    err = fillTransaction(transaction2, &callback2, layer2, false, true);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+                         ExpectedResult::Buffer::NOT_ACQUIRED);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MergeOneBufferOneColor) {
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    int err = fillTransaction(transaction1, &callback1, layer1);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    err = fillTransaction(transaction2, &callback2, layer2, false, true);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1);
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer2,
+                        ExpectedResult::Buffer::NOT_ACQUIRED);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
 TEST_F(LayerCallbackTest, Merge_SameCallback) {
     sp<SurfaceControl> layer1, layer2;
     ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
@@ -3870,10 +3970,11 @@
         LayerTransactionTest::SetUp();
         ASSERT_EQ(NO_ERROR, mClient->initCheck());
 
-        sp<IBinder> display(
-                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+        const auto display = SurfaceComposerClient::getInternalDisplayToken();
+        ASSERT_FALSE(display == nullptr);
+
         DisplayInfo info;
-        SurfaceComposerClient::getDisplayInfo(display, &info);
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
 
         ssize_t displayWidth = info.w;
         ssize_t displayHeight = info.h;
@@ -4334,7 +4435,7 @@
         mCapture->checkPixel(64, 64, 111, 111, 111);
     }
 
-    mChild->clear();
+    mChild.clear();
 
     {
         SCOPED_TRACE("After destroying child");
@@ -5025,23 +5126,35 @@
         SurfaceComposerClient::Transaction().show(mChild).apply(true);
     }
 
-    void verify() {
+    void verify(std::function<void()> verifyStartingState) {
+        // Verify starting state before a screenshot is taken.
+        verifyStartingState();
+
+        // Verify child layer does not inherit any of the properties of its
+        // parent when its screenshot is captured.
         auto fgHandle = mFGSurfaceControl->getHandle();
         ScreenCapture::captureChildLayers(&mCapture, fgHandle);
         mCapture->checkPixel(10, 10, 0, 0, 0);
         mCapture->expectChildColor(0, 0);
+
+        // Verify all assumptions are still true after the screenshot is taken.
+        verifyStartingState();
     }
 
     std::unique_ptr<ScreenCapture> mCapture;
     sp<SurfaceControl> mChild;
 };
 
+// Regression test b/76099859
 TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentVisibility) {
 
     SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
 
     // Even though the parent is hidden we should still capture the child.
-    verify();
+
+    // Before and after reparenting, verify child is properly hidden
+    // when rendering full-screen.
+    verify([&] { screenshot()->expectBGColor(64, 64); });
 }
 
 TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
@@ -5050,25 +5163,19 @@
             .apply(true);
 
     // Even though the parent is cropped out we should still capture the child.
-    verify();
+
+    // Before and after reparenting, verify child is cropped by parent.
+    verify([&] { screenshot()->expectBGColor(65, 65); });
 }
 
+// Regression test b/124372894
 TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) {
-
-    SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2);
+    SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2).apply(true);
 
     // We should not inherit the parent scaling.
-    verify();
-}
 
-TEST_F(ScreenCaptureChildOnlyTest, RegressionTest76099859) {
-    SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
-
-    // Even though the parent is hidden we should still capture the child.
-    verify();
-
-    // Verify everything was properly hidden when rendering the full-screen.
-    screenshot()->expectBGColor(0,0);
+    // Before and after reparenting, verify child is properly scaled.
+    verify([&] { screenshot()->expectChildColor(80, 80); });
 }
 
 
@@ -5206,7 +5313,7 @@
     ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
 
     auto redLayerHandle = redLayer->getHandle();
-    redLayer->clear();
+    redLayer.clear();
     SurfaceComposerClient::Transaction().apply(true);
 
     sp<GraphicBuffer> outBuffer;
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 68cf61e..a2c0611 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -31,7 +31,6 @@
         "libutils",
     ],
     static_libs: [
-        "libcompositionengine",
         "libgmock",
         "librenderengine",
         "libtrace_proto",
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 16e0891..f9e0b64 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -145,7 +145,7 @@
     void TearDown() override;
 
     void waitForDisplayTransaction();
-    bool waitForHotplugEvent(uint32_t id, bool connected);
+    bool waitForHotplugEvent(PhysicalDisplayId displayId, bool connected);
 
     sp<IComposer> mFakeService;
     sp<SurfaceComposerClient> mComposerClient;
@@ -242,7 +242,7 @@
     mMockComposer->runVSyncAndWait();
 }
 
-bool DisplayTest::waitForHotplugEvent(uint32_t id, bool connected) {
+bool DisplayTest::waitForHotplugEvent(PhysicalDisplayId displayId, bool connected) {
     int waitCount = 20;
     while (waitCount--) {
         while (!mReceivedDisplayEvents.empty()) {
@@ -250,11 +250,12 @@
             mReceivedDisplayEvents.pop_front();
 
             ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
-                    "event hotplug: id %d, connected %d\t", event.header.id,
-                    event.hotplug.connected);
+                     "event hotplug: displayId %" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+                     ", connected %d\t",
+                     event.header.displayId, event.hotplug.connected);
 
             if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG &&
-                event.header.id == id && event.hotplug.connected == connected) {
+                event.header.displayId == displayId && event.hotplug.connected == connected) {
                 return true;
             }
         }
@@ -294,13 +295,14 @@
 
     waitForDisplayTransaction();
 
-    EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, true));
+    EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
 
     {
-        sp<android::IBinder> display(
-                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
+        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+        ASSERT_FALSE(display == nullptr);
+
         DisplayInfo info;
-        SurfaceComposerClient::getDisplayInfo(display, &info);
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
         ASSERT_EQ(400u, info.w);
         ASSERT_EQ(200u, info.h);
 
@@ -328,14 +330,15 @@
 
     waitForDisplayTransaction();
 
-    EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, false));
-    EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, true));
+    EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
+    EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
 
     {
-        sp<android::IBinder> display(
-                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
+        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+        ASSERT_FALSE(display == nullptr);
+
         DisplayInfo info;
-        SurfaceComposerClient::getDisplayInfo(display, &info);
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
         ASSERT_EQ(400u, info.w);
         ASSERT_EQ(200u, info.h);
 
@@ -364,11 +367,12 @@
 
     waitForDisplayTransaction();
 
-    EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdMain, false));
+    EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, false));
 
     {
-        sp<android::IBinder> display(
-                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+        EXPECT_FALSE(display == nullptr);
+
         DisplayInfo info;
         auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
         EXPECT_NE(NO_ERROR, result);
@@ -402,11 +406,12 @@
 
     waitForDisplayTransaction();
 
-    EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdMain, true));
+    EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, true));
 
     {
-        sp<android::IBinder> display(
-                SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+        EXPECT_FALSE(display == nullptr);
+
         DisplayInfo info;
         auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
         EXPECT_EQ(NO_ERROR, result);
@@ -473,10 +478,11 @@
     ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
 
     ALOGI("TransactionTest::SetUp - display");
-    sp<android::IBinder> display(
-            SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+    ASSERT_FALSE(display == nullptr);
+
     DisplayInfo info;
-    SurfaceComposerClient::getDisplayInfo(display, &info);
+    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
 
     mDisplayWidth = info.w;
     mDisplayHeight = info.h;
diff --git a/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h b/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
index 2245ee1..8bed766 100644
--- a/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
+++ b/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
@@ -75,14 +75,16 @@
 template <typename... Args>
 class AsyncCallRecorder<void (*)(Args...)> {
 public:
-    // For the tests, we expect the wait for an expected change to be signaled
-    // to be much shorter than this.
-    static constexpr std::chrono::milliseconds DEFAULT_CALL_EXPECTED_TIMEOUT{10};
+    // This wait value needs to be large enough to avoid flakes caused by delays
+    // scheduling threads, but small enough that tests don't take forever if
+    // something really is wrong. Based on some empirical evidence, 100ms should
+    // be enough to avoid the former.
+    static constexpr std::chrono::milliseconds DEFAULT_CALL_EXPECTED_TIMEOUT{100};
 
-    // The wait here is tricky. We don't expect a change, but we don't want to
-    // wait forever (or for longer than the typical test function runtime). As
-    // even the simplest Google Test can take 1ms (1000us) to run, we wait for
-    // half that time.
+    // The wait here is tricky. It's for when We don't expect to record a call,
+    // but we don't want to wait forever (or for longer than the typical test
+    // function runtime). As even the simplest Google Test can take 1ms (1000us)
+    // to run, we wait for half that time.
     static constexpr std::chrono::microseconds UNEXPECTED_CALL_TIMEOUT{500};
 
     using ArgTuple = std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>;
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index e092aed..6deec29 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -17,6 +17,7 @@
 #undef LOG_TAG
 #define LOG_TAG "CompositionTest"
 
+#include <compositionengine/Display.h>
 #include <compositionengine/mock/DisplaySurface.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -32,6 +33,7 @@
 #include "ColorLayer.h"
 #include "Layer.h"
 
+#include "TestableScheduler.h"
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
 #include "mock/MockDispSync.h"
@@ -45,8 +47,10 @@
 
 using testing::_;
 using testing::AtLeast;
+using testing::Between;
 using testing::ByMove;
 using testing::DoAll;
+using testing::Field;
 using testing::Invoke;
 using testing::IsNull;
 using testing::Mock;
@@ -87,11 +91,9 @@
                 ::testing::UnitTest::GetInstance()->current_test_info();
         ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
 
-        mFlinger.mutableEventControlThread().reset(mEventControlThread);
-        mFlinger.mutableEventThread().reset(mEventThread);
         mFlinger.mutableEventQueue().reset(mMessageQueue);
+        setupScheduler();
 
-        mFlinger.mutablePrimaryDispSync().reset(mPrimaryDispSync);
         EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
         EXPECT_CALL(*mPrimaryDispSync, getPeriod())
                 .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
@@ -121,6 +123,18 @@
         Mock::VerifyAndClear(mComposer);
     }
 
+    void setupScheduler() {
+        mScheduler = new TestableScheduler();
+        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);
+
+        mFlinger.mutableScheduler().reset(mScheduler);
+    }
+
     void setupForceGeometryDirty() {
         // TODO: This requires the visible region and other related
         // state to be set, and is problematic for BufferLayers since they are
@@ -142,6 +156,7 @@
 
     std::unordered_set<HWC2::Capability> mDefaultCapabilities = {HWC2::Capability::SidebandStream};
 
+    TestableScheduler* mScheduler;
     TestableSurfaceFlinger mFlinger;
     sp<DisplayDevice> mDisplay;
     sp<DisplayDevice> mExternalDisplay;
@@ -152,14 +167,13 @@
     sp<GraphicBuffer> mBuffer = new GraphicBuffer();
     ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
 
-    mock::EventThread* mEventThread = new mock::EventThread();
+    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();
-    renderengine::mock::Image* mReImage = new renderengine::mock::Image();
     renderengine::mock::Framebuffer* mReFrameBuffer = new renderengine::mock::Framebuffer();
 
     sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
@@ -279,11 +293,10 @@
         EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
 
         EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
-        EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
-        EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
-
+        // TODO: remove once we verify that we can just grab the fence from the
+        // FramebufferSurface.
         EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() {
-            return base::unique_fd(0);
+            return base::unique_fd();
         }));
 
         EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
@@ -295,36 +308,18 @@
 
     template <typename Case>
     static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
-        // Called once with a non-null value to set a framebuffer, and then
-        // again with nullptr to clear it.
-        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull(), false))
-                .WillOnce(Return(true));
-        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull(), false))
-                .WillOnce(Return(true));
-
-        EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
-        EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
-                .WillOnce(Return(
-                        ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer))));
-        EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, clearWithColor(0, 0, 0, 1)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd())));
-        EXPECT_CALL(*test->mRenderEngine, finish()).WillOnce(Return(true));
-
-        EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(_)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
-                .Times(1);
-        // This expectation retires on saturation as setViewportAndProjection is
-        // called an extra time for the code path this setup is for.
-        // TODO: Investigate this extra call
-        EXPECT_CALL(*test->mRenderEngine,
-                    setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
-                                             Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
-                                             ui::Transform::ROT_0))
-                .Times(1)
-                .RetiresOnSaturation();
-        EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, drawLayers)
+                .WillRepeatedly(
+                        [](const renderengine::DisplaySettings& displaySettings,
+                           const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
+                           ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*) -> status_t {
+                            EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+                            EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                      displaySettings.physicalDisplay);
+                            EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                      displaySettings.clip);
+                            return NO_ERROR;
+                        });
     }
 
     static void setupNonEmptyFrameCompositionCallExpectations(CompositionTest* test) {
@@ -348,31 +343,23 @@
         EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
                 .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
 
-        EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
-                .Times(1);
-        EXPECT_CALL(*test->mRenderEngine, setColorTransform(_)).Times(2);
-        // These expectations retire on saturation as the code path these
-        // expectations are for appears to make an extra call to them.
-        // TODO: Investigate this extra call
-        EXPECT_CALL(*test->mRenderEngine,
-                    setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
-                                             Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
-                                             ui::Transform::ROT_0))
-                .Times(1);
-        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull(), false))
-                .WillOnce(Return(true));
-        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull(), false))
-                .WillOnce(Return(true));
-        EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
-                .WillOnce(Return(
-                        ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer))));
-        EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1);
         EXPECT_CALL(*test->mNativeWindow, queueBuffer(_, _)).WillOnce(Return(0));
         EXPECT_CALL(*test->mNativeWindow, dequeueBuffer(_, _))
                 .WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1),
                                 Return(0)));
+        EXPECT_CALL(*test->mRenderEngine, drawLayers)
+                .WillRepeatedly(
+                        [](const renderengine::DisplaySettings& displaySettings,
+                           const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
+                           ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*) -> status_t {
+                            EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+                            EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                      displaySettings.physicalDisplay);
+                            EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                      displaySettings.clip);
+                            EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace);
+                            return NO_ERROR;
+                        });
     }
 
     template <typename Case>
@@ -383,8 +370,6 @@
     template <typename Case>
     static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
         Case::Layer::setupREScreenshotCompositionCallExpectations(test);
-
-        EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
     }
 };
 
@@ -396,16 +381,11 @@
     template <typename Case>
     static void setupRELayerCompositionCallExpectations(CompositionTest* test) {
         Case::Layer::setupInsecureRECompositionCallExpectations(test);
-
-        // TODO: Investigate this extra call
-        EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
     }
 
     template <typename Case>
     static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
         Case::Layer::setupInsecureREScreenshotCompositionCallExpectations(test);
-
-        EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
     }
 };
 
@@ -514,9 +494,8 @@
 
         EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
         bool ignoredRecomputeVisibleRegions;
-        layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, Fence::NO_FENCE);
+        layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
         Mock::VerifyAndClear(test->mRenderEngine);
-        Mock::VerifyAndClear(test->mReImage);
     }
 
     static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
@@ -598,33 +577,36 @@
     }
 
     static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
-        EXPECT_CALL(*test->mRenderEngine,
-                    setupLayerBlending(true, false, false,
-                                       half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
-                                             LayerProperties::COLOR[2], LayerProperties::COLOR[3]),
-                                       0.0f))
-                .Times(1);
-
-        EXPECT_CALL(*test->mRenderEngine, createImage())
-                .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
-        EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, _)).WillOnce(Return(true));
-        EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, setupLayerTexturing(_)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1);
-        // This call retires on saturation as the code that renders a texture disables the state,
-        // along with a top-level disable to ensure it is disabled for non-buffer layers.
-        EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation();
+        EXPECT_CALL(*test->mRenderEngine, drawLayers)
+                .WillOnce([](const renderengine::DisplaySettings& displaySettings,
+                             const std::vector<renderengine::LayerSettings>& layerSettings,
+                             ANativeWindowBuffer*, base::unique_fd&&,
+                             base::unique_fd*) -> status_t {
+                    EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+                    EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                              displaySettings.physicalDisplay);
+                    EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                              displaySettings.clip);
+                    // screen capture adds an additional color layer as an alpha
+                    // prefill, so gtet the back layer.
+                    renderengine::LayerSettings layer = layerSettings.back();
+                    EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
+                    EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
+                    EXPECT_EQ(renderengine::Buffer::CachingHint::NO_CACHE,
+                              layer.source.buffer.cacheHint);
+                    EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName);
+                    EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
+                    EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
+                    EXPECT_EQ(false, layer.source.buffer.isOpaque);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+                    EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
+                    return NO_ERROR;
+                });
     }
 
     static void setupREBufferCompositionCallExpectations(CompositionTest* test) {
         LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
-
-        // TODO - Investigate and eliminate these differences between display
-        // composition and screenshot composition.
-        EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
     }
 
     static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
@@ -639,20 +621,29 @@
         LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
     }
 
-    static void setupREColorCompositionCommonCallExpectations(CompositionTest* test) {
-        EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
-    }
-
     static void setupREColorCompositionCallExpectations(CompositionTest* test) {
-        EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine,
-                    setupLayerBlending(true, false, true,
-                                       half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
-                                             LayerProperties::COLOR[2], LayerProperties::COLOR[3]),
-                                       0.0f))
-                .Times(1);
-        EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, drawLayers)
+                .WillOnce([](const renderengine::DisplaySettings& displaySettings,
+                             const std::vector<renderengine::LayerSettings>& layerSettings,
+                             ANativeWindowBuffer*, base::unique_fd&&,
+                             base::unique_fd*) -> status_t {
+                    EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+                    EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                              displaySettings.physicalDisplay);
+                    EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                              displaySettings.clip);
+                    // screen capture adds an additional color layer as an alpha
+                    // prefill, so get the back layer.
+                    renderengine::LayerSettings layer = layerSettings.back();
+                    EXPECT_THAT(layer.source.buffer.buffer, IsNull());
+                    EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+                                    LayerProperties::COLOR[2]),
+                              layer.source.solidColor);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+                    EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
+                    return NO_ERROR;
+                });
     }
 
     static void setupREColorScreenshotCompositionCallExpectations(CompositionTest* test) {
@@ -692,10 +683,7 @@
         EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
     }
 
-    static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
-        EXPECT_CALL(*test->mRenderEngine, setupFillWithColor(0, 0, 0, 1)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
-    }
+    static void setupREBufferCompositionCommonCallExpectations(CompositionTest* /*test*/) {}
 };
 
 struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties> {
@@ -704,25 +692,26 @@
     static constexpr uint32_t LAYER_FLAGS = ISurfaceComposerClient::eSecure;
 
     static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
-        EXPECT_CALL(*test->mRenderEngine, createImage())
-                .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
-        EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, _)).WillOnce(Return(true));
-        EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, setupLayerBlackedOut()).Times(1);
-
-        EXPECT_CALL(*test->mRenderEngine,
-                    setupLayerBlending(true, false, false,
-                                       half4(Base::COLOR[0], Base::COLOR[1], Base::COLOR[2],
-                                             Base::COLOR[3]),
-                                       0.0f))
-                .Times(1);
-        EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
-        EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1);
-        // This call retires on saturation as the code that renders a texture disables the state,
-        // along with a top-level disable to ensure it is disabled for non-buffer layers.
-        EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation();
+        EXPECT_CALL(*test->mRenderEngine, drawLayers)
+                .WillOnce([](const renderengine::DisplaySettings& displaySettings,
+                             const std::vector<renderengine::LayerSettings>& layerSettings,
+                             ANativeWindowBuffer*, base::unique_fd&&,
+                             base::unique_fd*) -> status_t {
+                    EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+                    EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                              displaySettings.physicalDisplay);
+                    EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                              displaySettings.clip);
+                    // screen capture adds an additional color layer as an alpha
+                    // prefill, so get the back layer.
+                    renderengine::LayerSettings layer = layerSettings.back();
+                    EXPECT_THAT(layer.source.buffer.buffer, IsNull());
+                    EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+                    EXPECT_EQ(1.0f, layer.alpha);
+                    return NO_ERROR;
+                });
     }
 
     static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
@@ -773,7 +762,7 @@
         layerDrawingState.active.h = 100;
         layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
                                         LayerProperties::COLOR[2], LayerProperties::COLOR[3]);
-
+        layer->computeBounds(FloatRect(0, 0, 100, 100), ui::Transform());
         layer->setVisibleRegion(Region(Rect(0, 0, 100, 100)));
 
         return layer;
@@ -783,9 +772,13 @@
         EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
                 .WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
 
-        const auto displayId = test->mDisplay->getId();
-        ASSERT_TRUE(displayId);
-        layer->createHwcLayer(&test->mFlinger.getHwComposer(), *displayId);
+        std::vector<std::unique_ptr<compositionengine::OutputLayer>> outputLayers;
+        outputLayers.emplace_back(test->mDisplay->getCompositionDisplay()
+                                          ->getOrCreateOutputLayer(DEFAULT_DISPLAY_ID,
+                                                                   layer->getCompositionLayer(),
+                                                                   layer));
+
+        test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(std::move(outputLayers));
 
         Mock::VerifyAndClear(test->mComposer);
 
@@ -798,11 +791,9 @@
     static void cleanupInjectedLayers(CompositionTest* test) {
         EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
                 .WillOnce(Return(Error::NONE));
-        const auto displayId = test->mDisplay->getId();
-        ASSERT_TRUE(displayId);
-        for (auto layer : test->mFlinger.mutableDrawingState().layersSortedByZ) {
-            layer->destroyHwcLayer(*displayId);
-        }
+
+        test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(
+                std::vector<std::unique_ptr<compositionengine::OutputLayer>>());
         test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
     }
 };
@@ -826,7 +817,6 @@
     }
 
     static void setupRECompositionCallExpectations(CompositionTest* test) {
-        LayerProperties::setupREColorCompositionCommonCallExpectations(test);
         LayerProperties::setupREColorCompositionCallExpectations(test);
     }
 
@@ -991,8 +981,8 @@
 };
 
 struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
-    static void setupLayerState(CompositionTest*, sp<Layer> layer) {
-        layer->forceClientComposition(DEFAULT_DISPLAY_ID);
+    static void setupLayerState(CompositionTest* test, sp<Layer> layer) {
+        layer->forceClientComposition(test->mDisplay);
     }
 
     template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index b7464d2..19f308b 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -29,6 +29,7 @@
 #include <ui/DebugUtils.h>
 
 #include "DisplayIdentificationTest.h"
+#include "TestableScheduler.h"
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
 #include "mock/MockDispSync.h"
@@ -45,9 +46,9 @@
 namespace {
 
 using testing::_;
-using testing::ByMove;
 using testing::DoAll;
 using testing::Mock;
+using testing::ResultOf;
 using testing::Return;
 using testing::SetArgPointee;
 
@@ -94,6 +95,8 @@
     DisplayTransactionTest();
     ~DisplayTransactionTest() override;
 
+    void setupScheduler();
+
     // --------------------------------------------------------------------
     // Mock/Fake injection
 
@@ -116,6 +119,7 @@
     // --------------------------------------------------------------------
     // Test instances
 
+    TestableScheduler* mScheduler;
     TestableSurfaceFlinger mFlinger;
     mock::EventThread* mEventThread = new mock::EventThread();
     mock::EventThread* mSFEventThread = new mock::EventThread();
@@ -160,13 +164,10 @@
         return nullptr;
     });
 
-    mFlinger.mutableEventControlThread().reset(mEventControlThread);
-    mFlinger.mutableEventThread().reset(mEventThread);
-    mFlinger.mutableSFEventThread().reset(mSFEventThread);
+    setupScheduler();
     mFlinger.mutableEventQueue().reset(mMessageQueue);
     mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
     mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
-    mFlinger.mutablePrimaryDispSync().reset(mPrimaryDispSync);
 
     injectMockComposer(0);
 }
@@ -177,6 +178,22 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
+void DisplayTransactionTest::setupScheduler() {
+    mScheduler = new TestableScheduler();
+    mScheduler->mutableEventControlThread().reset(mEventControlThread);
+    mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
+    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);
+}
+
 void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
     mComposer = new Hwc2::mock::Composer();
     EXPECT_CALL(*mComposer, getCapabilities())
@@ -321,11 +338,6 @@
     // Whether the display is primary
     static constexpr Primary PRIMARY = primary;
 
-    static constexpr auto displayType() {
-        return static_cast<bool>(PRIMARY) ? EventThread::DisplayType::Primary
-                                          : EventThread::DisplayType::External;
-    }
-
     static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
         auto injector =
                 FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
@@ -1111,8 +1123,8 @@
     // Preconditions
 
     // vsync is enabled and available
-    mFlinger.mutablePrimaryHWVsyncEnabled() = true;
-    mFlinger.mutableHWVsyncAvailable() = true;
+    mScheduler->mutablePrimaryHWVsyncEnabled() = true;
+    mScheduler->mutableHWVsyncAvailable() = true;
 
     // A display exists
     auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
@@ -1136,8 +1148,8 @@
     // Postconditions
 
     // vsyncs should be off and not available.
-    EXPECT_FALSE(mFlinger.mutablePrimaryHWVsyncEnabled());
-    EXPECT_FALSE(mFlinger.mutableHWVsyncAvailable());
+    EXPECT_FALSE(mScheduler->mutablePrimaryHWVsyncEnabled());
+    EXPECT_FALSE(mScheduler->mutableHWVsyncAvailable());
 
     // The display should have been removed from the display map.
     EXPECT_FALSE(hasDisplayDevice(existing.token()));
@@ -1497,6 +1509,9 @@
     template <typename Case>
     void setupCommonPreconditions();
 
+    template <typename Case, bool connected>
+    static void expectHotplugReceived(mock::EventThread*);
+
     template <typename Case>
     void setupCommonCallExpectationsForConnectProcessing();
 
@@ -1534,6 +1549,17 @@
     injectFakeNativeWindowSurfaceFactory();
 }
 
+template <typename Case, bool connected>
+void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* eventThread) {
+    const auto convert = [](auto physicalDisplayId) {
+        return std::make_optional(DisplayId{physicalDisplayId});
+    };
+
+    EXPECT_CALL(*eventThread,
+                onHotplugReceived(ResultOf(convert, Case::Display::DISPLAY_ID::get()), connected))
+            .Times(1);
+}
+
 template <typename Case>
 void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() {
     Case::Display::setupHwcHotplugCallExpectations(this);
@@ -1548,17 +1574,16 @@
     Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
 
     EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
-
-    EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::displayType(), true)).Times(1);
-    EXPECT_CALL(*mSFEventThread, onHotplugReceived(Case::Display::displayType(), true)).Times(1);
+    expectHotplugReceived<Case, true>(mEventThread);
+    expectHotplugReceived<Case, true>(mSFEventThread);
 }
 
 template <typename Case>
 void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
     EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
 
-    EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::displayType(), false)).Times(1);
-    EXPECT_CALL(*mSFEventThread, onHotplugReceived(Case::Display::displayType(), false)).Times(1);
+    expectHotplugReceived<Case, false>(mEventThread);
+    expectHotplugReceived<Case, false>(mSFEventThread);
 }
 
 template <typename Case>
@@ -2999,7 +3024,7 @@
     }
 
     static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) {
-        test->mFlinger.mutablePrimaryHWVsyncEnabled() = enabled;
+        test->mScheduler->mutablePrimaryHWVsyncEnabled() = enabled;
     }
 
     static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index dd90063..e499ff5 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -36,11 +36,15 @@
 namespace android {
 namespace {
 
+constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = 111;
+constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID = 222;
+
 class MockVSyncSource : public VSyncSource {
 public:
     MOCK_METHOD1(setVSyncEnabled, void(bool));
     MOCK_METHOD1(setCallback, void(VSyncSource::Callback*));
     MOCK_METHOD1(setPhaseOffset, void(nsecs_t));
+    MOCK_METHOD1(pauseVsyncCallback, void(bool));
 };
 
 } // namespace
@@ -50,8 +54,10 @@
     class MockEventThreadConnection : public EventThreadConnection {
     public:
         MockEventThreadConnection(android::impl::EventThread* eventThread,
-                                  ResyncCallback&& resyncCallback)
-              : EventThreadConnection(eventThread, std::move(resyncCallback)) {}
+                                  ResyncCallback&& resyncCallback,
+                                  ResetIdleTimerCallback&& resetIdleTimerCallback)
+              : EventThreadConnection(eventThread, std::move(resyncCallback),
+                                      std::move(resetIdleTimerCallback)) {}
         MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
     };
 
@@ -66,19 +72,22 @@
 
     void expectVSyncSetEnabledCallReceived(bool expectedState);
     void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset);
+    void expectVSyncPauseVsyncCallbackCallReceived(bool expectedPause);
     VSyncSource::Callback* expectVSyncSetCallbackCallReceived();
     void expectInterceptCallReceived(nsecs_t expectedTimestamp);
     void expectVsyncEventReceivedByConnection(const char* name,
                                               ConnectionEventRecorder& connectionEventRecorder,
                                               nsecs_t expectedTimestamp, unsigned expectedCount);
     void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
-    void expectHotplugEventReceivedByConnection(EventThread::DisplayType expectedDisplayType,
+    void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
                                                 bool expectedConnected);
 
     AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
     AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
     AsyncCallRecorder<void (*)(nsecs_t)> mVSyncSetPhaseOffsetCallRecorder;
+    AsyncCallRecorder<void (*)(bool)> mVSyncPauseVsyncCallbackCallRecorder;
     AsyncCallRecorder<void (*)()> mResyncCallRecorder;
+    AsyncCallRecorder<void (*)()> mResetIdleTimerCallRecorder;
     AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
     ConnectionEventRecorder mConnectionEventCallRecorder{0};
 
@@ -102,12 +111,15 @@
     EXPECT_CALL(mVSyncSource, setPhaseOffset(_))
             .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
 
+    EXPECT_CALL(mVSyncSource, pauseVsyncCallback(_))
+            .WillRepeatedly(Invoke(mVSyncPauseVsyncCallbackCallRecorder.getInvocable()));
+
     createThread();
     mConnection = createConnection(mConnectionEventCallRecorder);
 
     // A display must be connected for VSYNC events to be delivered.
-    mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
-    expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
+    mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true);
+    expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, true);
 }
 
 EventThreadTest::~EventThreadTest() {
@@ -116,7 +128,7 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 
     // EventThread should unregister itself as VSyncSource callback.
-    EXPECT_FALSE(expectVSyncSetCallbackCallReceived());
+    EXPECT_TRUE(!mVSyncSetCallbackCallRecorder.waitForUnexpectedCall().has_value());
 }
 
 void EventThreadTest::createThread() {
@@ -133,7 +145,8 @@
 sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
         ConnectionEventRecorder& recorder) {
     sp<MockEventThreadConnection> connection =
-            new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable());
+            new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable(),
+                                          mResetIdleTimerCallRecorder.getInvocable());
     EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
     return connection;
 }
@@ -150,6 +163,12 @@
     EXPECT_EQ(expectedPhaseOffset, std::get<0>(args.value()));
 }
 
+void EventThreadTest::expectVSyncPauseVsyncCallbackCallReceived(bool expectedPause) {
+    auto args = mVSyncPauseVsyncCallbackCallRecorder.waitForCall();
+    ASSERT_TRUE(args.has_value());
+    EXPECT_EQ(expectedPause, std::get<0>(args.value()));
+}
+
 VSyncSource::Callback* EventThreadTest::expectVSyncSetCallbackCallReceived() {
     auto callbackSet = mVSyncSetCallbackCallRecorder.waitForCall();
     return callbackSet.has_value() ? std::get<0>(callbackSet.value()) : nullptr;
@@ -183,16 +202,13 @@
                                          expectedCount);
 }
 
-void EventThreadTest::expectHotplugEventReceivedByConnection(
-        EventThread::DisplayType expectedDisplayType, bool expectedConnected) {
-    const uint32_t expectedDisplayId =
-            expectedDisplayType == EventThread::DisplayType::Primary ? 0 : 1;
-
+void EventThreadTest::expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
+                                                             bool expectedConnected) {
     auto args = mConnectionEventCallRecorder.waitForCall();
     ASSERT_TRUE(args.has_value());
     const auto& event = std::get<0>(args.value());
     EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, event.header.type);
-    EXPECT_EQ(expectedDisplayId, event.header.id);
+    EXPECT_EQ(expectedDisplayId, event.header.displayId);
     EXPECT_EQ(expectedConnected, event.hotplug.connected);
 }
 
@@ -207,13 +223,14 @@
     EXPECT_FALSE(mVSyncSetCallbackCallRecorder.waitForCall(0us).has_value());
     EXPECT_FALSE(mVSyncSetPhaseOffsetCallRecorder.waitForCall(0us).has_value());
     EXPECT_FALSE(mResyncCallRecorder.waitForCall(0us).has_value());
+    EXPECT_FALSE(mResetIdleTimerCallRecorder.waitForCall(0us).has_value());
     EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall(0us).has_value());
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value());
 }
 
 TEST_F(EventThreadTest, vsyncRequestIsIgnoredIfDisplayIsDisconnected) {
-    mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
-    expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
+    mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, false);
+    expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, false);
 
     // Signal that we want the next vsync event to be posted to the connection.
     mThread->requestNextVsync(mConnection, false);
@@ -224,9 +241,10 @@
 
 TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
     // Signal that we want the next vsync event to be posted to the connection
-    mThread->requestNextVsync(mConnection, false);
+    mThread->requestNextVsync(mConnection, true);
 
-    // EventThread should immediately request a resync.
+    // EventThread should immediately reset the idle timer and request a resync.
+    EXPECT_TRUE(mResetIdleTimerCallRecorder.waitForCall().has_value());
     EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
 
     // EventThread should enable vsync callbacks.
@@ -400,24 +418,34 @@
     expectVSyncSetPhaseOffsetCallReceived(321);
 }
 
-TEST_F(EventThreadTest, postHotplugPrimaryDisconnect) {
-    mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
-    expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
+TEST_F(EventThreadTest, pauseVsyncCallbackForwardsToVSyncSource) {
+    mThread->pauseVsyncCallback(true);
+    expectVSyncPauseVsyncCallbackCallReceived(true);
 }
 
-TEST_F(EventThreadTest, postHotplugPrimaryConnect) {
-    mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
-    expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
+TEST_F(EventThreadTest, resumeVsyncCallbackForwardsToVSyncSource) {
+    mThread->pauseVsyncCallback(false);
+    expectVSyncPauseVsyncCallbackCallReceived(false);
+}
+
+TEST_F(EventThreadTest, postHotplugInternalDisconnect) {
+    mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, false);
+    expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, false);
+}
+
+TEST_F(EventThreadTest, postHotplugInternalConnect) {
+    mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true);
+    expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, true);
 }
 
 TEST_F(EventThreadTest, postHotplugExternalDisconnect) {
-    mThread->onHotplugReceived(EventThread::DisplayType::External, false);
-    expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, false);
+    mThread->onHotplugReceived(EXTERNAL_DISPLAY_ID, false);
+    expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, false);
 }
 
 TEST_F(EventThreadTest, postHotplugExternalConnect) {
-    mThread->onHotplugReceived(EventThread::DisplayType::External, true);
-    expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, true);
+    mThread->onHotplugReceived(EXTERNAL_DISPLAY_ID, true);
+    expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, true);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
index 9fe9a18..5e82225 100644
--- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #undef LOG_TAG
 #define LOG_TAG "SchedulerUnittests"
 
@@ -34,93 +33,178 @@
     IdleTimerTest() = default;
     ~IdleTimerTest() override = default;
 
+    // This timeout should be used when a 3ms callback is expected.
+    // While the tests typically request a callback after 3ms, the scheduler
+    // does not always cooperate, at it can take significantly longer (observed
+    // 30ms).
+    static constexpr auto waitTimeForExpected3msCallback = 100ms;
+
+    // This timeout should be used when an 3ms callback is not expected.
+    // Note that there can be false-negatives if the callback happens later.
+    static constexpr auto waitTimeForUnexpected3msCallback = 6ms;
+
+    AsyncCallRecorder<void (*)()> mResetTimerCallback;
     AsyncCallRecorder<void (*)()> mExpiredTimerCallback;
 
     std::unique_ptr<IdleTimer> mIdleTimer;
+
+    void clearPendingCallbacks() {
+        while (mExpiredTimerCallback.waitForCall(0us).has_value()) {
+        }
+    }
 };
 
 namespace {
 TEST_F(IdleTimerTest, createAndDestroyTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, [] {});
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, [] {}, [] {});
 }
 
 TEST_F(IdleTimerTest, startStopTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mExpiredTimerCallback.getInvocable());
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mResetTimerCallback.getInvocable(),
+                                                        mExpiredTimerCallback.getInvocable());
+    auto startTime = std::chrono::steady_clock::now();
     mIdleTimer->start();
-    std::this_thread::sleep_for(std::chrono::milliseconds(10));
-    // The timer expires after 30 ms, so the call to the callback should not happen.
-    EXPECT_FALSE(mExpiredTimerCallback.waitForCall().has_value());
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+    // The idle timer fires after 30ms, so there should be no callback within
+    // 25ms (waiting for a callback for the full 30ms would be problematic).
+    bool callbackCalled = mExpiredTimerCallback.waitForCall(25ms).has_value();
+    // Under ideal conditions there should be no event. But occasionally
+    // it is possible that the wait just prior takes more than 30ms, and
+    // a callback is observed. We check the elapsed time since before the IdleTimer
+    // thread was started as a sanity check to not have a flakey test.
+    EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms);
+
+    std::this_thread::sleep_for(std::chrono::milliseconds(25));
+    EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
     mIdleTimer->stop();
 }
 
 TEST_F(IdleTimerTest, resetTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mExpiredTimerCallback.getInvocable());
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(),
+                                                        mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
-    std::this_thread::sleep_for(std::chrono::milliseconds(10));
-    // The timer expires after 30 ms, so the call to the callback should not happen.
-    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+    // Observe any event that happens in about 25ms. We don't care if one was
+    // observed or not.
+    mExpiredTimerCallback.waitForCall(25ms).has_value();
     mIdleTimer->reset();
-    // The timer was reset, so the call to the callback should not happen.
-    std::this_thread::sleep_for(std::chrono::milliseconds(15));
-    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+    // There may have been a race with the reset. Clear any callbacks we
+    // received right afterwards.
+    clearPendingCallbacks();
+    // A single callback should be generated after 30ms
+    EXPECT_TRUE(
+            mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback + 30ms).has_value());
+    // After one event, it should be idle, and not generate another.
+    EXPECT_FALSE(
+            mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback * 10).has_value());
     mIdleTimer->stop();
+    // Final quick check that no more callback were observed.
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
+    EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
+}
+
+TEST_F(IdleTimerTest, resetBackToBackTest) {
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(),
+                                                        mExpiredTimerCallback.getInvocable());
+    mIdleTimer->start();
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+
+    mIdleTimer->reset();
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+
+    mIdleTimer->reset();
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+
+    mIdleTimer->reset();
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+
+    mIdleTimer->reset();
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+
+    // A single callback should be generated after 30ms
+    EXPECT_TRUE(
+            mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback + 30ms).has_value());
+    mIdleTimer->stop();
+    // Final quick check that no more callback were observed.
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
+    EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
 }
 
 TEST_F(IdleTimerTest, startNotCalledTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
-    std::this_thread::sleep_for(6ms);
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
+                                                        mExpiredTimerCallback.getInvocable());
     // The start hasn't happened, so the callback does not happen.
-    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+    EXPECT_FALSE(mResetTimerCallback.waitForCall(1us).has_value());
     mIdleTimer->stop();
+    // Final quick check that no more callback were observed.
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
+    EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
 }
 
 TEST_F(IdleTimerTest, idleTimerIdlesTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
+                                                        mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
-    std::this_thread::sleep_for(6ms);
-    // The timer expires after 3 ms, so the call to the callback happens.
-    EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1us).has_value());
-    std::this_thread::sleep_for(6ms);
-    // Timer can be idle.
-    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
-    // Timer can be reset.
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+
+    // A callback should be generated after 3ms
+    EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
+    // After one event, it should be idle, and not generate another.
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+    // Once reset, it should generate another
     mIdleTimer->reset();
-    std::this_thread::sleep_for(6ms);
-    // Timer fires again.
-    EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    EXPECT_TRUE(mResetTimerCallback.waitForCall(1ms).has_value());
+    EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
     mIdleTimer->stop();
+    // Final quick check that no more callback were observed.
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
+    EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
 }
 
 TEST_F(IdleTimerTest, timeoutCallbackExecutionTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
-
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
+                                                        mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
-    std::this_thread::sleep_for(6ms);
-    // The timer expires after 3 ms, so the call to the callback should happen.
-    EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    EXPECT_TRUE(mResetTimerCallback.waitForCall(1us).has_value());
+    EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
     mIdleTimer->stop();
 }
 
 TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
+                                                        mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
-    std::this_thread::sleep_for(6ms);
-    EXPECT_TRUE(mExpiredTimerCallback.waitForCall().has_value());
+    EXPECT_TRUE(mResetTimerCallback.waitForCall(1ms).has_value());
+    EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
+
     mIdleTimer->stop();
+    clearPendingCallbacks();
     mIdleTimer->reset();
-    std::this_thread::sleep_for(6ms);
-    EXPECT_FALSE(mExpiredTimerCallback.waitForCall().has_value());
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+    EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value());
 }
 
 TEST_F(IdleTimerTest, noCallbacksAfterStopTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
+    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
+                                                        mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
-    std::this_thread::sleep_for(1ms);
+    EXPECT_TRUE(mResetTimerCallback.waitForCall(1ms).has_value());
+
     mIdleTimer->stop();
-    std::this_thread::sleep_for(3ms);
-    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(1us).has_value());
+    clearPendingCallbacks();
+    mIdleTimer->reset();
+
+    // No more idle events should be observed
+    EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+    EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value());
 }
 
 } // namespace
 } // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 4d9aec6..ec76538 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -18,12 +18,14 @@
 
 namespace android {
 
+constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = 999;
+
 class SchedulerTest : public testing::Test {
 protected:
     class MockEventThreadConnection : public android::EventThreadConnection {
     public:
         explicit MockEventThreadConnection(EventThread* eventThread)
-              : EventThreadConnection(eventThread, ResyncCallback()) {}
+              : EventThreadConnection(eventThread, ResyncCallback(), ResetIdleTimerCallback()) {}
         ~MockEventThreadConnection() = default;
 
         MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel));
@@ -76,7 +78,7 @@
 
     // createConnection call to scheduler makes a createEventConnection call to EventThread. Make
     // sure that call gets executed and returns an EventThread::Connection object.
-    EXPECT_CALL(*mEventThread, createEventConnection(_))
+    EXPECT_CALL(*mEventThread, createEventConnection(_, _))
             .WillRepeatedly(Return(mEventThreadConnection));
 
     mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(),
@@ -104,8 +106,7 @@
     EXPECT_TRUE(returnedValue == nullptr);
     EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
     EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
-    ASSERT_NO_FATAL_FAILURE(
-            mScheduler->hotplugReceived(nullptr, EventThread::DisplayType::Primary, false));
+    ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(nullptr, PHYSICAL_DISPLAY_ID, false));
     ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr));
     ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr));
     std::string testString;
@@ -129,8 +130,8 @@
 
     // The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads.
     EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0);
-    ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(connectionHandle,
-                                                        EventThread::DisplayType::Primary, false));
+    ASSERT_NO_FATAL_FAILURE(
+            mScheduler->hotplugReceived(connectionHandle, PHYSICAL_DISPLAY_ID, false));
 
     EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0);
     ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle));
@@ -158,10 +159,9 @@
     EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr);
     EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr);
 
-    EXPECT_CALL(*mEventThread, onHotplugReceived(EventThread::DisplayType::Primary, false))
-            .Times(1);
-    ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(mConnectionHandle,
-                                                        EventThread::DisplayType::Primary, false));
+    EXPECT_CALL(*mEventThread, onHotplugReceived(PHYSICAL_DISPLAY_ID, false)).Times(1);
+    ASSERT_NO_FATAL_FAILURE(
+            mScheduler->hotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false));
 
     EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1);
     ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle));
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
new file mode 100644
index 0000000..dcbf973
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -0,0 +1,65 @@
+/*
+ * 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 "Scheduler/EventThread.h"
+#include "Scheduler/Scheduler.h"
+
+namespace android {
+
+class TestableScheduler : public Scheduler {
+public:
+    TestableScheduler() : Scheduler([](bool) {}) {}
+
+    // Creates EventThreadConnection with the given eventThread. Creates Scheduler::Connection
+    // and adds it to the list of connectins. Returns the ConnectionHandle for the
+    // Scheduler::Connection. This allows plugging in mock::EventThread.
+    sp<Scheduler::ConnectionHandle> addConnection(std::unique_ptr<EventThread> eventThread) {
+        sp<EventThreadConnection> eventThreadConnection =
+                new EventThreadConnection(eventThread.get(), ResyncCallback(),
+                                          ResetIdleTimerCallback());
+        const int64_t id = sNextId++;
+        mConnections.emplace(id,
+                             std::make_unique<Scheduler::Connection>(new ConnectionHandle(id),
+                                                                     eventThreadConnection,
+                                                                     std::move(eventThread)));
+        return mConnections[id]->handle;
+    }
+
+    /* ------------------------------------------------------------------------
+     * Read-write access to private data to set up preconditions and assert
+     * post-conditions.
+     */
+    auto& mutablePrimaryHWVsyncEnabled() { return mPrimaryHWVsyncEnabled; }
+    auto& mutableEventControlThread() { return mEventControlThread; }
+    auto& mutablePrimaryDispSync() { return mPrimaryDispSync; }
+    auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; }
+
+    ~TestableScheduler() {
+        // All these pointer and container clears help ensure that GMock does
+        // not report a leaked object, since the Scheduler instance may
+        // still be referenced by something despite our best efforts to destroy
+        // it after each test is done.
+        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 e639b4d..6313f1f 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -16,7 +16,12 @@
 
 #pragma once
 
+#include <compositionengine/Display.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/CompositionEngine.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 
 #include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
@@ -203,9 +208,18 @@
 
     void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
         layer->mDrawingState.sidebandStream = sidebandStream;
-        layer->getBE().compositionInfo.hwc.sidebandStream = sidebandStream;
+        layer->mSidebandStream = sidebandStream;
+        layer->getCompositionLayer()->editState().frontEnd.sidebandStream = sidebandStream;
     }
 
+    void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
+        auto outputLayer = layer->findOutputLayerForDisplay(mFlinger->getDefaultDisplayDevice());
+        LOG_ALWAYS_FATAL_IF(!outputLayer);
+        auto& state = outputLayer->editState();
+        LOG_ALWAYS_FATAL_IF(!outputLayer->getState().hwc);
+        (*state.hwc).hwcCompositionType = static_cast<Hwc2::IComposerClient::Composition>(type);
+    };
+
     void setLayerPotentialCursor(sp<Layer> layer, bool potentialCursor) {
         layer->mPotentialCursor = potentialCursor;
     }
@@ -234,6 +248,7 @@
     }
 
     auto handleTransactionLocked(uint32_t transactionFlags) {
+        Mutex::Autolock _l(mFlinger->mStateLock);
         return mFlinger->handleTransactionLocked(transactionFlags);
     }
 
@@ -284,7 +299,6 @@
 
     const auto& getAnimFrameTracker() const { return mFlinger->mAnimFrameTracker; }
     const auto& getHasPoweredOff() const { return mFlinger->mHasPoweredOff; }
-    const auto& getHWVsyncAvailable() const { return mFlinger->mHWVsyncAvailable; }
     const auto& getVisibleRegionsDirty() const { return mFlinger->mVisibleRegionsDirty; }
     auto& getHwComposer() const {
         return static_cast<impl::HWComposer&>(mFlinger->getHwComposer());
@@ -305,18 +319,12 @@
     auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
     auto& mutableDisplays() { return mFlinger->mDisplays; }
     auto& mutableDrawingState() { return mFlinger->mDrawingState; }
-    auto& mutableEventControlThread() { return mFlinger->mEventControlThread; }
     auto& mutableEventQueue() { return mFlinger->mEventQueue; }
-    auto& mutableEventThread() { return mFlinger->mEventThread; }
-    auto& mutableSFEventThread() { return mFlinger->mSFEventThread; }
     auto& mutableGeometryInvalid() { return mFlinger->mGeometryInvalid; }
-    auto& mutableHWVsyncAvailable() { return mFlinger->mHWVsyncAvailable; }
     auto& mutableInterceptor() { return mFlinger->mInterceptor; }
     auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
     auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
     auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; }
-    auto& mutablePrimaryDispSync() { return mFlinger->mPrimaryDispSync; }
-    auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; }
     auto& mutableTexturePool() { return mFlinger->mTexturePool; }
     auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
     auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
@@ -326,6 +334,9 @@
     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; }
 
     ~TestableSurfaceFlinger() {
         // All these pointer and container clears help ensure that GMock does
@@ -333,12 +344,9 @@
         // still be referenced by something despite our best efforts to destroy
         // it after each test is done.
         mutableDisplays().clear();
-        mutableEventControlThread().reset();
         mutableEventQueue().reset();
-        mutableEventThread().reset();
-        mutableSFEventThread().reset();
         mutableInterceptor().reset();
-        mutablePrimaryDispSync().reset();
+        mutableScheduler().reset();
         mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
         mFlinger->mCompositionEngine->setRenderEngine(
                 std::unique_ptr<renderengine::RenderEngine>());
diff --git a/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp
index bc1f00d..ed628b8 100644
--- a/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp
+++ b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest_main.cpp
@@ -16,6 +16,11 @@
 
 #include <gtest/gtest.h>
 
+#include <sched.h>
+
+#include <processgroup/sched_policy.h>
+#include <system/graphics.h>
+
 #include "libsurfaceflinger_unittest_main.h"
 
 // ------------------------------------------------------------------------
@@ -39,6 +44,12 @@
 int main(int argc, char **argv) {
     ::testing::InitGoogleTest(&argc, argv);
 
+    // The SurfaceFlinger implementation assumes that threads resume
+    // execution as quickly as possible once they become unblocked.
+    // (These same calls are made in main_surfaceflinger.cpp)
+    setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+    set_sched_policy(0, SP_FOREGROUND);
+
     for (int i = 1; i < argc; i++) {
         if (strcmp(argv[i], "--no-slow") == 0) {
             g_noSlowTests = true;
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 3242ef1..5edee6e 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -28,16 +28,18 @@
     EventThread();
     ~EventThread() override;
 
-    MOCK_CONST_METHOD1(createEventConnection, sp<EventThreadConnection>(ResyncCallback));
+    MOCK_CONST_METHOD2(createEventConnection,
+                       sp<EventThreadConnection>(ResyncCallback, ResetIdleTimerCallback));
     MOCK_METHOD0(onScreenReleased, void());
     MOCK_METHOD0(onScreenAcquired, void());
-    MOCK_METHOD2(onHotplugReceived, void(DisplayType, bool));
+    MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
     MOCK_CONST_METHOD1(dump, void(std::string&));
     MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
     MOCK_METHOD1(registerDisplayEventConnection,
                  status_t(const sp<android::EventThreadConnection> &));
     MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
     MOCK_METHOD2(requestNextVsync, void(const sp<android::EventThreadConnection> &, bool));
+    MOCK_METHOD1(pauseVsyncCallback, void(bool));
 };
 
 } // namespace mock
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 164d9e6..a7fd912 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -91,11 +91,10 @@
 
   // Using placement new here to reuse shared memory instead of new allocation
   // and also initialize the value to zero.
-  buffer_state_ =
-      new (&metadata_header_->buffer_state) std::atomic<uint32_t>(0);
-  fence_state_ = new (&metadata_header_->fence_state) std::atomic<uint32_t>(0);
+  buffer_state_ = new (&metadata_header_->bufferState) std::atomic<uint32_t>(0);
+  fence_state_ = new (&metadata_header_->fenceState) std::atomic<uint32_t>(0);
   active_clients_bit_mask_ =
-      new (&metadata_header_->active_clients_bit_mask) std::atomic<uint32_t>(0);
+      new (&metadata_header_->activeClientsBitMask) std::atomic<uint32_t>(0);
 
   // Producer channel is never created after consumer channel, and one buffer
   // only have one fixed producer for now. Thus, it is correct to assume
@@ -183,7 +182,7 @@
                     buffer_.height(), buffer_.layer_count(), buffer_.format(),
                     buffer_.usage(),
                     buffer_state_->load(std::memory_order_acquire),
-                    signaled_mask, metadata_header_->queue_index);
+                    signaled_mask, metadata_header_->queueIndex);
 }
 
 void ProducerChannel::HandleImpulse(Message& message) {
@@ -253,7 +252,7 @@
   uint32_t current_active_clients_bit_mask =
       active_clients_bit_mask_->load(std::memory_order_acquire);
   uint32_t consumer_state_mask =
-      BufferHubDefs::FindNextAvailableClientStateMask(
+      BufferHubDefs::findNextAvailableClientStateMask(
           current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
   if (consumer_state_mask == 0U) {
     ALOGE("%s: reached the maximum mumber of consumers per producer: 63.",
@@ -279,7 +278,7 @@
           "condition.",
           __FUNCTION__, updated_active_clients_bit_mask,
           current_active_clients_bit_mask);
-    consumer_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
+    consumer_state_mask = BufferHubDefs::findNextAvailableClientStateMask(
         current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
     if (consumer_state_mask == 0U) {
       ALOGE("%s: reached the maximum mumber of consumers per producer: %d.",
@@ -337,13 +336,13 @@
   // consumer to a buffer that is available to producer (a.k.a a fully-released
   // buffer) or a gained buffer.
   if (current_buffer_state == 0U ||
-      BufferHubDefs::AnyClientGained(current_buffer_state)) {
+      BufferHubDefs::isAnyClientGained(current_buffer_state)) {
     return {status.take()};
   }
 
   // Signal the new consumer when adding it to a posted producer.
   bool update_buffer_state = true;
-  if (!BufferHubDefs::IsClientPosted(current_buffer_state,
+  if (!BufferHubDefs::isClientPosted(current_buffer_state,
                                      consumer_state_mask)) {
     uint32_t updated_buffer_state =
         current_buffer_state ^
@@ -360,7 +359,7 @@
           "released.",
           __FUNCTION__, current_buffer_state, updated_buffer_state);
       if (current_buffer_state == 0U ||
-          BufferHubDefs::AnyClientGained(current_buffer_state)) {
+          BufferHubDefs::isAnyClientGained(current_buffer_state)) {
         ALOGI("%s: buffer is gained or fully released, state=%" PRIx32 ".",
               __FUNCTION__, current_buffer_state);
         update_buffer_state = false;
@@ -371,7 +370,7 @@
           (consumer_state_mask & BufferHubDefs::kHighBitsMask);
     }
   }
-  if (update_buffer_state || BufferHubDefs::IsClientPosted(
+  if (update_buffer_state || BufferHubDefs::isClientPosted(
                                  buffer_state_->load(std::memory_order_acquire),
                                  consumer_state_mask)) {
     consumer->OnProducerPosted();
@@ -393,8 +392,8 @@
 Status<void> ProducerChannel::OnProducerPost(Message&,
                                              LocalFence acquire_fence) {
   ATRACE_NAME("ProducerChannel::OnProducerPost");
-  ALOGD("ProducerChannel::OnProducerPost: buffer_id=%d, state=0x%x",
-        buffer_id(), buffer_state_->load(std::memory_order_acquire));
+  ALOGD_IF(TRACE, "%s: buffer_id=%d, state=0x%x", __FUNCTION__, buffer_id(),
+           buffer_state_->load(std::memory_order_acquire));
 
   epoll_event event;
   event.events = 0;
@@ -438,7 +437,7 @@
 
 Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
   ATRACE_NAME("ProducerChannel::OnGain");
-  ALOGW("ProducerChannel::OnGain: buffer_id=%d", buffer_id());
+  ALOGD_IF(TRACE, "%s: buffer_id=%d", __FUNCTION__, buffer_id());
 
   ClearAvailable();
   post_fence_.close();
@@ -457,7 +456,7 @@
            buffer_id());
 
   uint32_t buffer_state = buffer_state_->load(std::memory_order_acquire);
-  if (!BufferHubDefs::IsClientGained(
+  if (!BufferHubDefs::isClientGained(
       buffer_state, BufferHubDefs::kFirstClientStateMask)) {
     // Can only detach a ProducerBuffer when it's in gained state.
     ALOGW(
@@ -547,7 +546,7 @@
           "%s: orphaned buffer detected during the this acquire/release cycle: "
           "id=%d orphaned=0x%" PRIx32 " queue_index=%" PRId64 ".",
           __FUNCTION__, buffer_id(), orphaned_consumer_bit_mask_,
-          metadata_header_->queue_index);
+          metadata_header_->queueIndex);
       orphaned_consumer_bit_mask_ = 0;
     }
   }
@@ -581,7 +580,7 @@
       "consumer_state_mask=%" PRIx32 " queue_index=%" PRId64
       " buffer_state=%" PRIx32 " fence_state=%" PRIx32 ".",
       __FUNCTION__, buffer_id(), consumer_state_mask,
-      metadata_header_->queue_index,
+      metadata_header_->queueIndex,
       buffer_state_->load(std::memory_order_acquire),
       fence_state_->load(std::memory_order_acquire));
 }
@@ -616,9 +615,9 @@
 
   const uint32_t current_buffer_state =
       buffer_state_->load(std::memory_order_acquire);
-  if (BufferHubDefs::IsClientPosted(current_buffer_state,
+  if (BufferHubDefs::isClientPosted(current_buffer_state,
                                     consumer_state_mask) ||
-      BufferHubDefs::IsClientAcquired(current_buffer_state,
+      BufferHubDefs::isClientAcquired(current_buffer_state,
                                       consumer_state_mask)) {
     // The consumer client is being destoryed without releasing. This could
     // happen in corner cases when the consumer crashes. Here we mark it
@@ -627,9 +626,9 @@
     return;
   }
 
-  if (BufferHubDefs::IsClientReleased(current_buffer_state,
+  if (BufferHubDefs::isClientReleased(current_buffer_state,
                                       consumer_state_mask) ||
-      BufferHubDefs::AnyClientGained(current_buffer_state)) {
+      BufferHubDefs::isAnyClientGained(current_buffer_state)) {
     // The consumer is being close while it is suppose to signal a release
     // fence. Signal the dummy fence here.
     if (fence_state_->load(std::memory_order_acquire) & consumer_state_mask) {
diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp
index 6b33f50..004dc7c 100644
--- a/services/vr/bufferhubd/producer_queue_channel.cpp
+++ b/services/vr/bufferhubd/producer_queue_channel.cpp
@@ -323,7 +323,7 @@
   // memory to indicate which client is the last producer of the buffer.
   // Currently, the first client is the only producer to the buffer.
   // Thus, it checks whether the first client gains the buffer below.
-  if (!BufferHubDefs::IsClientGained(buffer_state,
+  if (!BufferHubDefs::isClientGained(buffer_state,
                                      BufferHubDefs::kFirstClientBitMask)) {
     // Rejects the request if the requested buffer is not in Gained state.
     ALOGE(
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index fed8481..206c8eb 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -84,8 +84,8 @@
         "libutils",
         "libcutils",
         "libz",
-        "libnativebridge",
-        "libnativeloader",
+        "libnativebridge_lazy",
+        "libnativeloader_lazy",
         "libnativewindow",
         "android.hardware.graphics.common@1.0",
     ],
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 673a066..71048db 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -21,6 +21,8 @@
 // There are a few of them requiring manual code for things such as layer
 // discovery or chaining.  They call into functions defined in this file.
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include <stdlib.h>
 #include <string.h>
 
@@ -32,6 +34,7 @@
 #include <android-base/strings.h>
 #include <cutils/properties.h>
 #include <log/log.h>
+#include <utils/Trace.h>
 
 #include <vulkan/vk_layer_interface.h>
 #include <graphicsenv/GraphicsEnv.h>
@@ -1176,6 +1179,8 @@
 VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo,
                         const VkAllocationCallbacks* pAllocator,
                         VkInstance* pInstance) {
+    ATRACE_CALL();
+
     if (!EnsureInitialized())
         return VK_ERROR_INITIALIZATION_FAILED;
 
@@ -1184,6 +1189,8 @@
 
 void DestroyInstance(VkInstance instance,
                      const VkAllocationCallbacks* pAllocator) {
+    ATRACE_CALL();
+
     if (instance != VK_NULL_HANDLE)
         LayerChain::DestroyInstance(instance, pAllocator);
 }
@@ -1192,17 +1199,23 @@
                       const VkDeviceCreateInfo* pCreateInfo,
                       const VkAllocationCallbacks* pAllocator,
                       VkDevice* pDevice) {
+    ATRACE_CALL();
+
     return LayerChain::CreateDevice(physicalDevice, pCreateInfo, pAllocator,
                                     pDevice);
 }
 
 void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
+    ATRACE_CALL();
+
     if (device != VK_NULL_HANDLE)
         LayerChain::DestroyDevice(device, pAllocator);
 }
 
 VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount,
                                           VkLayerProperties* pProperties) {
+    ATRACE_CALL();
+
     if (!EnsureInitialized())
         return VK_ERROR_INITIALIZATION_FAILED;
 
@@ -1225,6 +1238,8 @@
     const char* pLayerName,
     uint32_t* pPropertyCount,
     VkExtensionProperties* pProperties) {
+    ATRACE_CALL();
+
     if (!EnsureInitialized())
         return VK_ERROR_INITIALIZATION_FAILED;
 
@@ -1253,6 +1268,8 @@
 VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,
                                         uint32_t* pPropertyCount,
                                         VkLayerProperties* pProperties) {
+    ATRACE_CALL();
+
     uint32_t count;
     const LayerChain::ActiveLayer* layers =
         LayerChain::GetActiveLayers(physicalDevice, count);
@@ -1275,6 +1292,8 @@
     const char* pLayerName,
     uint32_t* pPropertyCount,
     VkExtensionProperties* pProperties) {
+    ATRACE_CALL();
+
     if (pLayerName) {
         // EnumerateDeviceLayerProperties enumerates active layers for
         // backward compatibility.  The extension query here should work for
@@ -1302,6 +1321,8 @@
 }
 
 VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) {
+    ATRACE_CALL();
+
     *pApiVersion = VK_API_VERSION_1_1;
     return VK_SUCCESS;
 }
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a607a5d..b3259de 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include <malloc.h>
 #include <stdlib.h>
 #include <string.h>
@@ -31,6 +33,8 @@
 #include <configstore/Utils.h>
 #include <cutils/properties.h>
 #include <graphicsenv/GraphicsEnv.h>
+#include <utils/Timers.h>
+#include <utils/Trace.h>
 #include <utils/Vector.h>
 
 #include "android-base/properties.h"
@@ -150,6 +154,8 @@
 void* LoadLibrary(const android_dlextinfo& dlextinfo,
                   const char* subname,
                   int subname_len) {
+    ATRACE_CALL();
+
     const char kLibFormat[] = "vulkan.%*s.so";
     char* name = static_cast<char*>(
         alloca(sizeof(kLibFormat) + static_cast<size_t>(subname_len)));
@@ -164,6 +170,8 @@
 
 int LoadDriver(android_namespace_t* library_namespace,
                const hwvulkan_module_t** module) {
+    ATRACE_CALL();
+
     const android_dlextinfo dlextinfo = {
         .flags = ANDROID_DLEXT_USE_NAMESPACE,
         .library_namespace = library_namespace,
@@ -198,20 +206,32 @@
 }
 
 int LoadBuiltinDriver(const hwvulkan_module_t** module) {
+    ATRACE_CALL();
+
     auto ns = android_get_exported_namespace("sphal");
     if (!ns)
         return -ENOENT;
+    android::GraphicsEnv::getInstance().setDriverToLoad(
+        android::GraphicsEnv::Driver::VULKAN);
     return LoadDriver(ns, module);
 }
 
 int LoadUpdatedDriver(const hwvulkan_module_t** module) {
+    ATRACE_CALL();
+
     auto ns = android::GraphicsEnv::getInstance().getDriverNamespace();
     if (!ns)
         return -ENOENT;
+    android::GraphicsEnv::getInstance().setDriverToLoad(
+        android::GraphicsEnv::Driver::VULKAN_UPDATED);
     return LoadDriver(ns, module);
 }
 
 bool Hal::Open() {
+    ATRACE_CALL();
+
+    const nsecs_t openTime = systemTime();
+
     ALOG_ASSERT(!hal_.dev_, "OpenHAL called more than once");
 
     // Use a stub device unless we successfully open a real HAL device.
@@ -237,15 +257,22 @@
         }
     }
     if (result != 0) {
+        android::GraphicsEnv::getInstance().setDriverLoaded(
+            android::GraphicsEnv::Api::API_VK, false, systemTime() - openTime);
         ALOGV("unable to load Vulkan HAL, using stub HAL (result=%d)", result);
         return true;
     }
 
+
     hwvulkan_device_t* device;
+    ATRACE_BEGIN("hwvulkan module open");
     result =
         module->common.methods->open(&module->common, HWVULKAN_DEVICE_0,
                                      reinterpret_cast<hw_device_t**>(&device));
+    ATRACE_END();
     if (result != 0) {
+        android::GraphicsEnv::getInstance().setDriverLoaded(
+            android::GraphicsEnv::Api::API_VK, false, systemTime() - openTime);
         // Any device with a Vulkan HAL should be able to open the device.
         ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result),
               result);
@@ -256,10 +283,15 @@
 
     hal_.InitDebugReportIndex();
 
+    android::GraphicsEnv::getInstance().setDriverLoaded(
+        android::GraphicsEnv::Api::API_VK, true, systemTime() - openTime);
+
     return true;
 }
 
 bool Hal::InitDebugReportIndex() {
+    ATRACE_CALL();
+
     uint32_t count;
     if (dev_->EnumerateInstanceExtensionProperties(nullptr, &count, nullptr) !=
         VK_SUCCESS) {
@@ -821,8 +853,10 @@
         }
     }
 
+    ATRACE_BEGIN("driver.EnumerateInstanceExtensionProperties");
     VkResult result = Hal::Device().EnumerateInstanceExtensionProperties(
         pLayerName, pPropertyCount, pProperties);
+    ATRACE_END();
 
     if (!pLayerName && (result == VK_SUCCESS || result == VK_INCOMPLETE)) {
         int idx = Hal::Get().GetDebugReportIndex();
@@ -931,8 +965,10 @@
         *pPropertyCount -= count;
     }
 
+    ATRACE_BEGIN("driver.EnumerateDeviceExtensionProperties");
     VkResult result = data.driver.EnumerateDeviceExtensionProperties(
         physicalDevice, pLayerName, pPropertyCount, pProperties);
+    ATRACE_END();
 
     if (pProperties) {
         // map VK_ANDROID_native_buffer to VK_KHR_swapchain
@@ -968,12 +1004,15 @@
     if (result != VK_SUCCESS)
         return result;
 
+    ATRACE_BEGIN("AllocateInstanceData");
     InstanceData* data = AllocateInstanceData(data_allocator);
+    ATRACE_END();
     if (!data)
         return VK_ERROR_OUT_OF_HOST_MEMORY;
 
     data->hook_extensions |= wrapper.GetHookExtensions();
 
+    ATRACE_BEGIN("autoDowngradeApiVersion");
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wold-style-cast"
     uint32_t api_version = ((pCreateInfo->pApplicationInfo)
@@ -989,7 +1028,9 @@
     if (!pfn_enumerate_instance_version) {
         icd_api_version = VK_API_VERSION_1_0;
     } else {
+        ATRACE_BEGIN("pfn_enumerate_instance_version");
         result = (*pfn_enumerate_instance_version)(&icd_api_version);
+        ATRACE_END();
     }
     uint32_t icd_api_major_version = VK_VERSION_MAJOR(icd_api_version);
     uint32_t icd_api_minor_version = VK_VERSION_MINOR(icd_api_version);
@@ -1000,12 +1041,15 @@
         wrapper.DowngradeApiVersion();
     }
 #pragma clang diagnostic pop
+    ATRACE_END();
 
     // call into the driver
     VkInstance instance;
+    ATRACE_BEGIN("driver.CreateInstance");
     result = Hal::Device().CreateInstance(
         static_cast<const VkInstanceCreateInfo*>(wrapper), pAllocator,
         &instance);
+    ATRACE_END();
     if (result != VK_SUCCESS) {
         FreeInstanceData(data, data_allocator);
         return result;
@@ -1066,8 +1110,10 @@
     if (result != VK_SUCCESS)
         return result;
 
+    ATRACE_BEGIN("AllocateDeviceData");
     DeviceData* data = AllocateDeviceData(data_allocator,
                                           instance_data.debug_report_callbacks);
+    ATRACE_END();
     if (!data)
         return VK_ERROR_OUT_OF_HOST_MEMORY;
 
@@ -1075,9 +1121,11 @@
 
     // call into the driver
     VkDevice dev;
+    ATRACE_BEGIN("driver.CreateDevice");
     result = instance_data.driver.CreateDevice(
         physicalDevice, static_cast<const VkDeviceCreateInfo*>(wrapper),
         pAllocator, &dev);
+    ATRACE_END();
     if (result != VK_SUCCESS) {
         FreeDeviceData(data, data_allocator);
         return result;
@@ -1114,8 +1162,10 @@
     }
 
     VkPhysicalDeviceProperties properties;
+    ATRACE_BEGIN("driver.GetPhysicalDeviceProperties");
     instance_data.driver.GetPhysicalDeviceProperties(physicalDevice,
                                                      &properties);
+    ATRACE_END();
 
     data->driver_device = dev;
     data->driver_version = properties.driverVersion;
@@ -1141,6 +1191,8 @@
 VkResult EnumeratePhysicalDevices(VkInstance instance,
                                   uint32_t* pPhysicalDeviceCount,
                                   VkPhysicalDevice* pPhysicalDevices) {
+    ATRACE_CALL();
+
     const auto& data = GetData(instance);
 
     VkResult result = data.driver.EnumeratePhysicalDevices(
@@ -1157,6 +1209,8 @@
     VkInstance instance,
     uint32_t* pPhysicalDeviceGroupCount,
     VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+    ATRACE_CALL();
+
     VkResult result = VK_SUCCESS;
     const auto& data = GetData(instance);
 
@@ -1217,6 +1271,8 @@
                     uint32_t queueFamilyIndex,
                     uint32_t queueIndex,
                     VkQueue* pQueue) {
+    ATRACE_CALL();
+
     const auto& data = GetData(device);
 
     data.driver.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
@@ -1226,6 +1282,8 @@
 void GetDeviceQueue2(VkDevice device,
                      const VkDeviceQueueInfo2* pQueueInfo,
                      VkQueue* pQueue) {
+    ATRACE_CALL();
+
     const auto& data = GetData(device);
 
     data.driver.GetDeviceQueue2(device, pQueueInfo, pQueue);
@@ -1236,6 +1294,8 @@
 AllocateCommandBuffers(VkDevice device,
                        const VkCommandBufferAllocateInfo* pAllocateInfo,
                        VkCommandBuffer* pCommandBuffers) {
+    ATRACE_CALL();
+
     const auto& data = GetData(device);
 
     VkResult result = data.driver.AllocateCommandBuffers(device, pAllocateInfo,
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index ba4cf00..af1adcf 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include "layers_extensions.h"
 
 #include <alloca.h>
@@ -33,6 +35,7 @@
 #include <log/log.h>
 #include <nativebridge/native_bridge.h>
 #include <nativeloader/native_loader.h>
+#include <utils/Trace.h>
 #include <ziparchive/zip_archive.h>
 
 // TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
@@ -428,6 +431,8 @@
 }
 
 void DiscoverLayersInPathList(const std::string& pathstr) {
+    ATRACE_CALL();
+
     std::vector<std::string> paths = android::base::Split(pathstr, ":");
     for (const auto& path : paths) {
         ForEachFileInPath(path, [&](const std::string& filename) {
@@ -477,6 +482,8 @@
 }  // anonymous namespace
 
 void DiscoverLayers() {
+    ATRACE_CALL();
+
     if (property_get_bool("ro.debuggable", false) &&
         prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
         DiscoverLayersInPathList(kSystemLayerLibraryDir);
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 8601373..73fc7b2 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include <algorithm>
 
 #include <grallocusage/GrallocUsageConversion.h>
@@ -21,6 +23,7 @@
 #include <ui/BufferQueueDefs.h>
 #include <sync/sync.h>
 #include <utils/StrongPointer.h>
+#include <utils/Trace.h>
 #include <utils/Vector.h>
 #include <system/window.h>
 #include <android/hardware/graphics/common/1.0/types.h>
@@ -416,7 +419,7 @@
         case VK_FORMAT_R16G16B16A16_SFLOAT:
             native_format = HAL_PIXEL_FORMAT_RGBA_FP16;
             break;
-        case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+        case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
             native_format = HAL_PIXEL_FORMAT_RGBA_1010102;
             break;
         default:
@@ -486,6 +489,8 @@
     const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
     const VkAllocationCallbacks* allocator,
     VkSurfaceKHR* out_surface) {
+    ATRACE_CALL();
+
     if (!allocator)
         allocator = &GetData(instance).allocator;
     void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface),
@@ -528,6 +533,8 @@
 void DestroySurfaceKHR(VkInstance instance,
                        VkSurfaceKHR surface_handle,
                        const VkAllocationCallbacks* allocator) {
+    ATRACE_CALL();
+
     Surface* surface = SurfaceFromHandle(surface_handle);
     if (!surface)
         return;
@@ -548,6 +555,8 @@
                                             uint32_t /*queue_family*/,
                                             VkSurfaceKHR surface_handle,
                                             VkBool32* supported) {
+    ATRACE_CALL();
+
     const Surface* surface = SurfaceFromHandle(surface_handle);
     if (!surface) {
         return VK_ERROR_SURFACE_LOST_KHR;
@@ -570,6 +579,7 @@
         case HAL_PIXEL_FORMAT_RGBA_8888:
         case HAL_PIXEL_FORMAT_RGB_565:
         case HAL_PIXEL_FORMAT_RGBA_FP16:
+        case HAL_PIXEL_FORMAT_RGBA_1010102:
             format_supported = true;
             break;
         default:
@@ -589,6 +599,8 @@
     VkPhysicalDevice /*pdev*/,
     VkSurfaceKHR surface,
     VkSurfaceCapabilitiesKHR* capabilities) {
+    ATRACE_CALL();
+
     int err;
     ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
 
@@ -662,6 +674,8 @@
                                             VkSurfaceKHR surface_handle,
                                             uint32_t* count,
                                             VkSurfaceFormatKHR* formats) {
+    ATRACE_CALL();
+
     const InstanceData& instance_data = GetData(pdev);
 
     // TODO(jessehall): Fill out the set of supported formats. Longer term, add
@@ -674,6 +688,8 @@
         {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
         {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
         {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+        {VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+        {VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
     };
     const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
     uint32_t total_num_formats = kNumFormats;
@@ -700,6 +716,8 @@
          VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
         {VK_FORMAT_R16G16B16A16_SFLOAT,
          VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT},
+        {VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+         VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
     };
     const uint32_t kNumWideColorFormats =
         sizeof(kWideColorFormats) / sizeof(kWideColorFormats[0]);
@@ -734,6 +752,8 @@
     VkPhysicalDevice physicalDevice,
     const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
     VkSurfaceCapabilities2KHR* pSurfaceCapabilities) {
+    ATRACE_CALL();
+
     VkResult result = GetPhysicalDeviceSurfaceCapabilitiesKHR(
         physicalDevice, pSurfaceInfo->surface,
         &pSurfaceCapabilities->surfaceCapabilities);
@@ -769,6 +789,8 @@
     const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
     uint32_t* pSurfaceFormatCount,
     VkSurfaceFormat2KHR* pSurfaceFormats) {
+    ATRACE_CALL();
+
     if (!pSurfaceFormats) {
         return GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,
                                                   pSurfaceInfo->surface,
@@ -800,6 +822,8 @@
                                                  VkSurfaceKHR surface,
                                                  uint32_t* count,
                                                  VkPresentModeKHR* modes) {
+    ATRACE_CALL();
+
     int err;
     int query_value;
     ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
@@ -851,6 +875,8 @@
 VkResult GetDeviceGroupPresentCapabilitiesKHR(
     VkDevice,
     VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
+    ATRACE_CALL();
+
     ALOGV_IF(pDeviceGroupPresentCapabilities->sType !=
                  VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR,
              "vkGetDeviceGroupPresentCapabilitiesKHR: invalid "
@@ -873,6 +899,8 @@
     VkDevice,
     VkSurfaceKHR,
     VkDeviceGroupPresentModeFlagsKHR* pModes) {
+    ATRACE_CALL();
+
     *pModes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
     return VK_SUCCESS;
 }
@@ -882,6 +910,8 @@
                                                VkSurfaceKHR surface,
                                                uint32_t* pRectCount,
                                                VkRect2D* pRects) {
+    ATRACE_CALL();
+
     if (!pRects) {
         *pRectCount = 1;
     } else {
@@ -923,6 +953,8 @@
                             const VkSwapchainCreateInfoKHR* create_info,
                             const VkAllocationCallbacks* allocator,
                             VkSwapchainKHR* swapchain_handle) {
+    ATRACE_CALL();
+
     int err;
     VkResult result = VK_SUCCESS;
 
@@ -1147,9 +1179,11 @@
     int32_t legacy_usage = 0;
     if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
         uint64_t consumer_usage, producer_usage;
+        ATRACE_BEGIN("dispatch.GetSwapchainGrallocUsage2ANDROID");
         result = dispatch.GetSwapchainGrallocUsage2ANDROID(
             device, create_info->imageFormat, create_info->imageUsage,
             swapchain_image_usage, &consumer_usage, &producer_usage);
+        ATRACE_END();
         if (result != VK_SUCCESS) {
             ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
             return VK_ERROR_SURFACE_LOST_KHR;
@@ -1157,9 +1191,11 @@
         legacy_usage =
             android_convertGralloc1To0Usage(producer_usage, consumer_usage);
     } else if (dispatch.GetSwapchainGrallocUsageANDROID) {
+        ATRACE_BEGIN("dispatch.GetSwapchainGrallocUsageANDROID");
         result = dispatch.GetSwapchainGrallocUsageANDROID(
             device, create_info->imageFormat, create_info->imageUsage,
             &legacy_usage);
+        ATRACE_END();
         if (result != VK_SUCCESS) {
             ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
             return VK_ERROR_SURFACE_LOST_KHR;
@@ -1254,8 +1290,10 @@
             &image_native_buffer.usage2.producer,
             &image_native_buffer.usage2.consumer);
 
+        ATRACE_BEGIN("dispatch.CreateImage");
         result =
             dispatch.CreateImage(device, &image_create, nullptr, &img.image);
+        ATRACE_END();
         if (result != VK_SUCCESS) {
             ALOGD("vkCreateImage w/ native buffer failed: %u", result);
             break;
@@ -1279,8 +1317,11 @@
             }
         }
         if (result != VK_SUCCESS) {
-            if (img.image)
+            if (img.image) {
+                ATRACE_BEGIN("dispatch.DestroyImage");
                 dispatch.DestroyImage(device, img.image, nullptr);
+                ATRACE_END();
+            }
         }
     }
 
@@ -1299,6 +1340,8 @@
 void DestroySwapchainKHR(VkDevice device,
                          VkSwapchainKHR swapchain_handle,
                          const VkAllocationCallbacks* allocator) {
+    ATRACE_CALL();
+
     const auto& dispatch = GetData(device).driver;
     Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
     if (!swapchain)
@@ -1324,6 +1367,8 @@
                                VkSwapchainKHR swapchain_handle,
                                uint32_t* count,
                                VkImage* images) {
+    ATRACE_CALL();
+
     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
     ALOGW_IF(swapchain.surface.swapchain_handle != swapchain_handle,
              "getting images for non-active swapchain 0x%" PRIx64
@@ -1352,6 +1397,8 @@
                              VkSemaphore semaphore,
                              VkFence vk_fence,
                              uint32_t* image_index) {
+    ATRACE_CALL();
+
     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
     ANativeWindow* window = swapchain.surface.window.get();
     VkResult result;
@@ -1432,6 +1479,8 @@
 VkResult AcquireNextImage2KHR(VkDevice device,
                               const VkAcquireNextImageInfoKHR* pAcquireInfo,
                               uint32_t* pImageIndex) {
+    ATRACE_CALL();
+
     // TODO: this should actually be the other way around and this function
     // should handle any additional structures that get passed in
     return AcquireNextImageKHR(device, pAcquireInfo->swapchain,
@@ -1461,6 +1510,8 @@
 
 VKAPI_ATTR
 VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
+    ATRACE_CALL();
+
     ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
              "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
              present_info->sType);
@@ -1672,6 +1723,8 @@
     VkDevice,
     VkSwapchainKHR swapchain_handle,
     VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) {
+    ATRACE_CALL();
+
     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
     VkResult result = VK_SUCCESS;
 
@@ -1687,6 +1740,8 @@
     VkSwapchainKHR swapchain_handle,
     uint32_t* count,
     VkPastPresentationTimingGOOGLE* timings) {
+    ATRACE_CALL();
+
     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
     ANativeWindow* window = swapchain.surface.window.get();
     VkResult result = VK_SUCCESS;
@@ -1711,6 +1766,8 @@
 VkResult GetSwapchainStatusKHR(
     VkDevice,
     VkSwapchainKHR swapchain_handle) {
+    ATRACE_CALL();
+
     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
     VkResult result = VK_SUCCESS;
 
@@ -1728,6 +1785,7 @@
     uint32_t swapchainCount,
     const VkSwapchainKHR* pSwapchains,
     const VkHdrMetadataEXT* pHdrMetadataEXTs) {
+    ATRACE_CALL();
 
     for (uint32_t idx = 0; idx < swapchainCount; idx++) {
         Swapchain* swapchain = SwapchainFromHandle(pSwapchains[idx]);