Merge "Move PublicFormat from libandroid_runtime to libui"
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index bb089e6..ddae9ea 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_ANOTHER_REPORT_IN_PROGRESS);
+        }
+        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/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..ea1e467 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_ANOTHER_REPORT_IN_PROGRESS = 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 27abee2..03a15bb 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -158,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));
@@ -166,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;
@@ -461,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 {
@@ -768,6 +766,17 @@
                ZipWriter::ErrorCodeString(err));
         return UNKNOWN_ERROR;
     }
+    bool finished_entry = false;
+    auto finish_entry = [this, &finished_entry] {
+        if (!finished_entry) {
+            // This should only be called when we're going to return an earlier error,
+            // which would've been logged. This may imply the file is already corrupt
+            // and any further logging from FinishEntry is more likely to mislead than
+            // not.
+            this->zip_writer_->FinishEntry();
+        }
+    };
+    auto scope_guard = android::base::make_scope_guard(finish_entry);
     auto start = std::chrono::steady_clock::now();
     auto end = start + timeout;
     struct pollfd pfd = {fd, POLLIN};
@@ -784,11 +793,11 @@
 
             int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
             if (rc < 0) {
-                MYLOGE("Error in poll while adding from fd to zip entry %s:%s", entry_name.c_str(),
-                       strerror(errno));
+                MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
+                       entry_name.c_str(), strerror(errno));
                 return -errno;
             } else if (rc == 0) {
-                MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms",
+                MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
                        entry_name.c_str(), strerror(errno), timeout.count());
                 return TIMED_OUT;
             }
@@ -809,6 +818,7 @@
     }
 
     err = zip_writer_->FinishEntry();
+    finished_entry = true;
     if (err != 0) {
         MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
         return UNKNOWN_ERROR;
@@ -1331,6 +1341,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);
@@ -1592,13 +1603,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());
@@ -1759,9 +1765,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;
 }
@@ -2345,6 +2349,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;
@@ -2491,15 +2496,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 */
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 9f99114..fc3642c 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_;
 };
 
 /**
@@ -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_ANOTHER_REPORT_IN_PROGRESS);
+
+    // 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/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 528e43d..4bc0e1d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -108,6 +108,8 @@
         if (log_only_) {
             MYLOGD("Duration of '%s': %.3fs\n", title_.c_str(), (float)elapsed / NANOS_PER_SEC);
         } else {
+            // TODO(124089395): Remove or rewrite when bugreport latency is fixed.
+            MYLOGD("Duration of '%s': %.3fs\n", title_.c_str(), (float)elapsed / NANOS_PER_SEC);
             // Use "Yoda grammar" to make it easier to grep|sort sections.
             printf("------ %.3fs was the duration of '%s' ------\n", (float)elapsed / NANOS_PER_SEC,
                    title_.c_str());
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index e33b2a8..b60bbc0 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -35,6 +35,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
 
     product_variables: {
@@ -227,6 +228,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
 }
 
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 852aa79..f523725 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -45,6 +45,7 @@
 #include <private/android_filesystem_config.h>
 #include <processgroup/sched_policy.h>
 #include <selinux/android.h>
+#include <server_configurable_flags/get_flags.h>
 #include <system/thread_defs.h>
 
 #include "dexopt.h"
@@ -260,6 +261,13 @@
   return "";
 }
 
+// Namespace for Android Runtime flags applied during boot time.
+static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
+// Feature flag name for running the JIT in Zygote experiment, b/119800099.
+static const char* ENABLE_APEX_IMAGE = "enable_apex_image";
+// Location of the apex image.
+static const char* kApexImage = "/system/framework/apex.art";
+
 class RunDex2Oat : public ExecVHelper {
   public:
     RunDex2Oat(int zip_fd,
@@ -293,6 +301,14 @@
                 : "dalvik.vm.boot-dex2oat-threads";
         std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
 
+        std::string bootclasspath;
+        char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH");
+        if (dex2oat_bootclasspath != nullptr) {
+            bootclasspath = StringPrintf("-Xbootclasspath:%s", dex2oat_bootclasspath);
+        }
+        // If DEX2OATBOOTCLASSPATH is not in the environment, dex2oat is going to query
+        // BOOTCLASSPATH.
+
         const std::string dex2oat_isa_features_key =
                 StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
         std::string instruction_set_features_arg =
@@ -352,6 +368,17 @@
         bool generate_minidebug_info = kEnableMinidebugInfo &&
                 GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
 
+        std::string boot_image;
+        std::string use_apex_image =
+            server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
+                                                                 ENABLE_APEX_IMAGE,
+                                                                 /*default_value=*/ "");
+        if (use_apex_image == "true") {
+          boot_image = StringPrintf("-Ximage:%s", kApexImage);
+        } else {
+          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 +393,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 +464,8 @@
         AddArg(instruction_set_variant_arg);
         AddArg(instruction_set_features_arg);
 
+        AddRuntimeArg(boot_image);
+        AddRuntimeArg(bootclasspath);
         AddRuntimeArg(dex2oat_Xms_arg);
         AddRuntimeArg(dex2oat_Xmx_arg);
 
@@ -468,7 +497,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,11 +1987,6 @@
         /* 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/globals.cpp b/cmds/installd/globals.cpp
index b3a6daf..f52c2e7 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -44,6 +44,8 @@
 static constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under
                                                                   // ANDROID_DATA
 
+static constexpr const char* STAGING_SUBDIR = "pkg_staging/"; // sub-directory under ANDROID_DATA
+
 std::string android_app_dir;
 std::string android_app_ephemeral_dir;
 std::string android_app_lib_dir;
@@ -54,6 +56,7 @@
 std::string android_mnt_expand_dir;
 std::string android_profiles_dir;
 std::string android_root_dir;
+std::string android_staging_dir;
 
 std::vector<std::string> android_system_dirs;
 
@@ -110,6 +113,9 @@
     // Get the android profiles directory.
     android_profiles_dir = android_data_dir + PROFILES_SUBDIR;
 
+    // Get the android session staging directory.
+    android_staging_dir = android_data_dir + STAGING_SUBDIR;
+
     // Take note of the system and vendor directories.
     android_system_dirs.clear();
     android_system_dirs.push_back(android_root_dir + APP_SUBDIR);
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index 633e33b..a88a86e 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -38,6 +38,7 @@
 extern std::string android_mnt_expand_dir;
 extern std::string android_profiles_dir;
 extern std::string android_root_dir;
+extern std::string android_staging_dir;
 
 extern std::vector<std::string> android_system_dirs;
 
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 9c9db0f..1ed49a0 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -31,6 +31,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "libdiskusage",
@@ -54,6 +55,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "libdiskusage",
@@ -77,6 +79,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "libdiskusage",
@@ -96,6 +99,7 @@
         "libbase",
         "libcutils",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "liblog",
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 48b07c4..a31d510 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -259,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",
@@ -296,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));
@@ -318,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);
 
@@ -339,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 */));
@@ -349,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);
 
@@ -380,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(
@@ -421,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",
@@ -491,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));
@@ -500,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 */));
@@ -542,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(
@@ -553,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(
@@ -588,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.
@@ -598,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 */));
@@ -639,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;
@@ -648,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..da097db 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);
 }
@@ -892,6 +928,8 @@
 static int validate_apk_path_internal(const std::string& path, int maxSubdirs) {
     if (validate_path(android_app_dir, path, maxSubdirs) == 0) {
         return 0;
+    } else if (validate_path(android_staging_dir, path, maxSubdirs) == 0) {
+        return 0;
     } else if (validate_path(android_app_private_dir, path, maxSubdirs) == 0) {
         return 0;
     } else if (validate_path(android_app_ephemeral_dir, path, maxSubdirs) == 0) {
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/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 ce8db91..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;
 };
 
 /*
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 566c334..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 {
@@ -55,11 +56,23 @@
      */
     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 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/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index 5b66b92..ccde12a 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -54,4 +54,9 @@
 
     long getVersionCodeForPackage(in String packageName);
 
+    /**
+     * Return if each app, identified by its package name allows its audio to be recorded.
+     * Unknown packages are mapped to false.
+     */
+    boolean[] isAudioPlaybackCaptureAllowed(in @utf8InCpp String[] packageNames);
 }
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 386f9f0..13c0d87 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -146,36 +146,39 @@
     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,
-                              const std::string& driverBuildDate,
-                              const std::string& appPackageName) {
+                              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[%llu]\n"
-          "\tdriverBuildDate[%s]\n"
+          "\tdriverVersionCode[%" PRIu64 "]\n"
+          "\tdriverBuildTime[%" PRId64 "]\n"
           "\tappPackageName[%s]\n",
-          driverPackageName.c_str(), driverVersionName.c_str(),
-          (unsigned long long)driverVersionCode, driverBuildDate.c_str(), appPackageName.c_str());
+          driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
+          appPackageName.c_str());
 
     mGpuStats.driverPackageName = driverPackageName;
     mGpuStats.driverVersionName = driverVersionName;
     mGpuStats.driverVersionCode = driverVersionCode;
-    mGpuStats.driverBuildDate = driverBuildDate;
+    mGpuStats.driverBuildTime = driverBuildTime;
     mGpuStats.appPackageName = appPackageName;
 }
 
@@ -264,21 +267,20 @@
     ALOGV("sendGpuStats:\n"
           "\tdriverPackageName[%s]\n"
           "\tdriverVersionName[%s]\n"
-          "\tdriverVersionCode[%llu]\n"
-          "\tdriverBuildDate[%s]\n"
+          "\tdriverVersionCode[%" PRIu64 "]\n"
+          "\tdriverBuildTime[%" PRId64 "]\n"
           "\tappPackageName[%s]\n"
           "\tdriver[%d]\n"
           "\tisDriverLoaded[%d]\n"
-          "\tdriverLoadingTime[%lld]",
+          "\tdriverLoadingTime[%" PRId64 "]",
           mGpuStats.driverPackageName.c_str(), mGpuStats.driverVersionName.c_str(),
-          (unsigned long long)mGpuStats.driverVersionCode, mGpuStats.driverBuildDate.c_str(),
-          mGpuStats.appPackageName.c_str(), static_cast<int32_t>(driver), isDriverLoaded,
-          (long long)driverLoadingTime);
+          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.driverBuildDate,
+                                mGpuStats.driverVersionCode, mGpuStats.driverBuildTime,
                                 mGpuStats.appPackageName, driver, isDriverLoaded,
                                 driverLoadingTime);
     }
@@ -538,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
index a8a07c2..f755e00 100644
--- a/libs/graphicsenv/IGpuService.cpp
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -29,7 +29,7 @@
 
     virtual void setGpuStats(const std::string& driverPackageName,
                              const std::string& driverVersionName, uint64_t driverVersionCode,
-                             const std::string& driverBuildDate, const std::string& appPackageName,
+                             int64_t driverBuildTime, const std::string& appPackageName,
                              GraphicsEnv::Driver driver, bool isDriverLoaded,
                              int64_t driverLoadingTime) {
         Parcel data, reply;
@@ -38,7 +38,7 @@
         data.writeUtf8AsUtf16(driverPackageName);
         data.writeUtf8AsUtf16(driverVersionName);
         data.writeUint64(driverVersionCode);
-        data.writeUtf8AsUtf16(driverBuildDate);
+        data.writeInt64(driverBuildTime);
         data.writeUtf8AsUtf16(appPackageName);
         data.writeInt32(static_cast<int32_t>(driver));
         data.writeBool(isDriverLoaded);
@@ -68,8 +68,8 @@
             uint64_t driverVersionCode;
             if ((status = data.readUint64(&driverVersionCode)) != OK) return status;
 
-            std::string driverBuildDate;
-            if ((status = data.readUtf8FromUtf16(&driverBuildDate)) != 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;
@@ -83,7 +83,7 @@
             int64_t driverLoadingTime;
             if ((status = data.readInt64(&driverLoadingTime)) != OK) return status;
 
-            setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildDate,
+            setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
                         appPackageName, static_cast<GraphicsEnv::Driver>(driver), isDriverLoaded,
                         driverLoadingTime);
 
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsAtoms.h b/libs/graphicsenv/include/graphicsenv/GpuStatsAtoms.h
new file mode 100644
index 0000000..f8b0ad7
--- /dev/null
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsAtoms.h
@@ -0,0 +1,42 @@
+/*
+ * 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 <string>
+#include <vector>
+
+namespace android {
+
+struct GpuStatsGlobalAtom {
+    std::string driverPackageName = "";
+    std::string driverVersionName = "";
+    uint64_t driverVersionCode = 0;
+    int64_t driverBuildTime = 0;
+    int32_t glLoadingCount = 0;
+    int32_t glLoadingFailureCount = 0;
+    int32_t vkLoadingCount = 0;
+    int32_t vkLoadingFailureCount = 0;
+};
+
+struct GpuStatsAppAtom {
+    std::string appPackageName = "";
+    uint64_t driverVersionCode = 0;
+    std::vector<int64_t> glDriverLoadingTime = {};
+    std::vector<int64_t> vkDriverLoadingTime = {};
+};
+
+} // namespace android
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 20b0205..cb4239f 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -48,7 +48,7 @@
         std::string driverPackageName;
         std::string driverVersionName;
         uint64_t driverVersionCode;
-        std::string driverBuildDate;
+        int64_t driverBuildTime;
         std::string appPackageName;
         Driver glDriverToLoad;
         Driver glDriverFallback;
@@ -59,7 +59,7 @@
               : driverPackageName(""),
                 driverVersionName(""),
                 driverVersionCode(0),
-                driverBuildDate(""),
+                driverBuildTime(0),
                 appPackageName(""),
                 glDriverToLoad(Driver::NONE),
                 glDriverFallback(Driver::NONE),
@@ -77,10 +77,13 @@
     // (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, const std::string& driverBuildDate,
+                     uint64_t versionCode, int64_t driverBuildTime,
                      const std::string& appPackageName);
     void setDriverToLoad(Driver driver);
     void setDriverLoaded(Api api, bool isDriverLoaded, int64_t driverLoadingTime);
@@ -118,6 +121,7 @@
 
     GraphicsEnv() = default;
     std::string mDriverPath;
+    std::string mSphalLibraries;
     std::mutex mStatsLock;
     GpuStats mGpuStats;
     std::string mAnglePath;
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
index 105a903..5f9340d 100644
--- a/libs/graphicsenv/include/graphicsenv/IGpuService.h
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -35,7 +35,7 @@
     // set GPU stats from GraphicsEnvironment.
     virtual void setGpuStats(const std::string& driverPackageName,
                              const std::string& driverVersionName, uint64_t driverVersionCode,
-                             const std::string& driverBuildDate, const std::string& appPackageName,
+                             int64_t driverBuildTime, const std::string& appPackageName,
                              GraphicsEnv::Driver driver, bool isDriverLoaded,
                              int64_t driverLoadingTime) = 0;
 };
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index f77eeb2..400daf0 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -100,7 +100,7 @@
                                    const ui::Dataspace reqDataspace,
                                    const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                                   ISurfaceComposer::Rotation rotation) {
+                                   ISurfaceComposer::Rotation rotation, bool captureSecureLayers) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
@@ -111,6 +111,7 @@
         data.writeUint32(reqHeight);
         data.writeInt32(static_cast<int32_t>(useIdentityTransform));
         data.writeInt32(static_cast<int32_t>(rotation));
+        data.writeInt32(static_cast<int32_t>(captureSecureLayers));
         status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
         if (result != NO_ERROR) {
             ALOGE("captureScreen failed to transact: %d", result);
@@ -791,21 +792,74 @@
         Parcel data, reply;
         status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (error != NO_ERROR) {
-            ALOGE("addRegionSamplingListener: Failed to write interface token");
+            ALOGE("removeRegionSamplingListener: Failed to write interface token");
             return error;
         }
         error = data.writeStrongBinder(IInterface::asBinder(listener));
         if (error != NO_ERROR) {
-            ALOGE("addRegionSamplingListener: Failed to write listener");
+            ALOGE("removeRegionSamplingListener: 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");
+            ALOGE("removeRegionSamplingListener: Failed to transact");
         }
         return error;
     }
+
+    virtual status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                              const std::vector<int32_t>& allowedConfigs) {
+        Parcel data, reply;
+        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("setAllowedDisplayConfigs failed to writeInterfaceToken: %d", result);
+            return result;
+        }
+        result = data.writeStrongBinder(displayToken);
+        if (result != NO_ERROR) {
+            ALOGE("setAllowedDisplayConfigs failed to writeStrongBinder: %d", result);
+            return result;
+        }
+        result = data.writeInt32Vector(allowedConfigs);
+        if (result != NO_ERROR) {
+            ALOGE("setAllowedDisplayConfigs failed to writeInt32Vector: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::SET_ALLOWED_DISPLAY_CONFIGS, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("setAllowedDisplayConfigs failed to transact: %d", result);
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                              std::vector<int32_t>* outAllowedConfigs) {
+        if (!outAllowedConfigs) return BAD_VALUE;
+        Parcel data, reply;
+        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("getAllowedDisplayConfigs failed to writeInterfaceToken: %d", result);
+            return result;
+        }
+        result = data.writeStrongBinder(displayToken);
+        if (result != NO_ERROR) {
+            ALOGE("getAllowedDisplayConfigs failed to writeStrongBinder: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::GET_ALLOWED_DISPLAY_CONFIGS, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getAllowedDisplayConfigs failed to transact: %d", result);
+            return result;
+        }
+        result = reply.readInt32Vector(outAllowedConfigs);
+        if (result != NO_ERROR) {
+            ALOGE("getAllowedDisplayConfigs failed to readInt32Vector: %d", result);
+            return result;
+        }
+        return reply.readInt32();
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -884,10 +938,11 @@
             uint32_t reqHeight = data.readUint32();
             bool useIdentityTransform = static_cast<bool>(data.readInt32());
             int32_t rotation = data.readInt32();
+            bool captureSecureLayers = static_cast<bool>(data.readInt32());
 
             status_t res = captureScreen(display, &outBuffer, reqDataspace, reqPixelFormat,
                                          sourceCrop, reqWidth, reqHeight, useIdentityTransform,
-                                         static_cast<ISurfaceComposer::Rotation>(rotation));
+                                         static_cast<ISurfaceComposer::Rotation>(rotation), captureSecureLayers);
             reply->writeInt32(res);
             if (res == NO_ERROR) {
                 reply->write(*outBuffer);
@@ -1317,6 +1372,24 @@
             }
             return removeRegionSamplingListener(listener);
         }
+        case SET_ALLOWED_DISPLAY_CONFIGS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> displayToken = data.readStrongBinder();
+            std::vector<int32_t> allowedConfigs;
+            data.readInt32Vector(&allowedConfigs);
+            status_t result = setAllowedDisplayConfigs(displayToken, allowedConfigs);
+            reply->writeInt32(result);
+            return result;
+        }
+        case GET_ALLOWED_DISPLAY_CONFIGS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> displayToken = data.readStrongBinder();
+            std::vector<int32_t> allowedConfigs;
+            status_t result = getAllowedDisplayConfigs(displayToken, &allowedConfigs);
+            reply->writeInt32Vector(allowedConfigs);
+            reply->writeInt32(result);
+            return result;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp
index 745433a..04d2871 100644
--- a/libs/gui/LayerMetadata.cpp
+++ b/libs/gui/LayerMetadata.cpp
@@ -31,10 +31,23 @@
 
 LayerMetadata::LayerMetadata(LayerMetadata&& other) = default;
 
-void LayerMetadata::merge(const LayerMetadata& other) {
+bool LayerMetadata::merge(const LayerMetadata& other, bool eraseEmpty) {
+    bool changed = false;
     for (const auto& entry : other.mMap) {
-        mMap[entry.first] = entry.second;
+        auto it = mMap.find(entry.first);
+        if (it != mMap.cend() && it->second != entry.second) {
+            if (eraseEmpty && entry.second.empty()) {
+                mMap.erase(it);
+            } else {
+                it->second = entry.second;
+            }
+            changed = true;
+        } else if (it == mMap.cend() && !entry.second.empty()) {
+            mMap[entry.first] = entry.second;
+            changed = true;
+        }
     }
+    return changed;
 }
 
 status_t LayerMetadata::writeToParcel(Parcel* parcel) const {
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/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index bf2a03d..7a39222 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1083,6 +1083,11 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() {
+    mInputWindowCommands.syncInputWindows = true;
+    return *this;
+}
+
 #endif
 
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorTransform(
@@ -1377,6 +1382,18 @@
     return ComposerService::getComposerService()->setActiveConfig(display, id);
 }
 
+status_t SurfaceComposerClient::setAllowedDisplayConfigs(
+        const sp<IBinder>& displayToken, const std::vector<int32_t>& allowedConfigs) {
+    return ComposerService::getComposerService()->setAllowedDisplayConfigs(displayToken,
+                                                                           allowedConfigs);
+}
+
+status_t SurfaceComposerClient::getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                                         std::vector<int32_t>* outAllowedConfigs) {
+    return ComposerService::getComposerService()->getAllowedDisplayConfigs(displayToken,
+                                                                           outAllowedConfigs);
+}
+
 status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
         Vector<ColorMode>* outColorModes) {
     return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes);
@@ -1464,18 +1481,27 @@
 status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
                                    const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                                   uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
+                                   uint32_t rotation, bool captureSecureLayers, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
     status_t ret = s->captureScreen(display, outBuffer, reqDataSpace, reqPixelFormat, sourceCrop,
-                                    reqWidth, reqHeight, useIdentityTransform,
-                                    static_cast<ISurfaceComposer::Rotation>(rotation));
+            reqWidth, reqHeight, useIdentityTransform,
+            static_cast<ISurfaceComposer::Rotation>(rotation),
+            captureSecureLayers);
     if (ret != NO_ERROR) {
         return ret;
     }
     return ret;
 }
 
+status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                   uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                                   uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
+    return capture(display, reqDataSpace, reqPixelFormat, sourceCrop, reqWidth,
+            reqHeight, useIdentityTransform, rotation, false, outBuffer);
+}
+
 status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
                                          const ui::Dataspace reqDataSpace,
                                          const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 8c3f463..22de751 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -52,6 +52,7 @@
     enum {
         DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
         DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
+        DISPLAY_EVENT_CONFIG_CHANGED = fourcc('c', 'o', 'n', 'f'),
     };
 
     struct Event {
@@ -70,10 +71,15 @@
             bool connected;
         };
 
+        struct Config {
+            int32_t configId;
+        };
+
         Header header;
         union {
             VSync vsync;
             Hotplug hotplug;
+            Config config;
         };
     };
 
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 1a0b6bb..0e576ca 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -209,7 +209,8 @@
                                    const ui::Dataspace reqDataspace,
                                    const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                                   Rotation rotation = eRotateNone) = 0;
+                                   Rotation rotation = eRotateNone,
+                                   bool captureSecureLayers = false) = 0;
     /**
      * Capture the specified screen. This requires READ_FRAME_BUFFER
      * permission.  This function will fail if there is a secure window on
@@ -359,6 +360,22 @@
      * Removes a listener that was streaming median luma updates from SurfaceFlinger.
      */
     virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0;
+
+    /*
+     * Sets the allowed display configurations to be used.
+     * The allowedConfigs in a vector of indexes corresponding to the configurations
+     * returned from getDisplayConfigs().
+     */
+    virtual status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                              const std::vector<int32_t>& allowedConfigs) = 0;
+
+    /*
+     * Returns the allowed display configurations currently set.
+     * The allowedConfigs in a vector of indexes corresponding to the configurations
+     * returned from getDisplayConfigs().
+     */
+    virtual status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                              std::vector<int32_t>* outAllowedConfigs) = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -406,6 +423,8 @@
         GET_PHYSICAL_DISPLAY_IDS,
         ADD_REGION_SAMPLING_LISTENER,
         REMOVE_REGION_SAMPLING_LISTENER,
+        SET_ALLOWED_DISPLAY_CONFIGS,
+        GET_ALLOWED_DISPLAY_CONFIGS,
         // Always append new enum to the end.
     };
 
diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
index 3ae10e4..47f0ced 100644
--- a/libs/gui/include/gui/LayerMetadata.h
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -34,7 +34,9 @@
     LayerMetadata& operator=(const LayerMetadata& other);
     LayerMetadata& operator=(LayerMetadata&& other);
 
-    void merge(const LayerMetadata& other);
+    // Merges other into this LayerMetadata. If eraseEmpty is true, any entries in
+    // in this whose keys are paired with empty values in other will be erased.
+    bool merge(const LayerMetadata& other, bool eraseEmpty = false);
 
     status_t writeToParcel(Parcel* parcel) const override;
     status_t readFromParcel(const Parcel* parcel) override;
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 aa99bd2..e062339 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -111,6 +111,18 @@
     // returned by getDisplayInfo
     static status_t setActiveConfig(const sp<IBinder>& display, int id);
 
+    // Sets the allowed display configurations to be used.
+    // The allowedConfigs in a vector of indexes corresponding to the configurations
+    // returned from getDisplayConfigs().
+    static status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                             const std::vector<int32_t>& allowedConfigs);
+
+    // Returns the allowed display configurations currently set.
+    // The allowedConfigs in a vector of indexes corresponding to the configurations
+    // returned from getDisplayConfigs().
+    static status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                             std::vector<int32_t>* outAllowedConfigs);
+
     // Gets the list of supported color modes for the given display
     static status_t getDisplayColorModes(const sp<IBinder>& display,
             Vector<ui::ColorMode>* outColorModes);
@@ -378,6 +390,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.
@@ -453,6 +466,10 @@
     static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
                             const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                             uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                            uint32_t rotation, bool captureSecureLayers, sp<GraphicBuffer>* outBuffer);
+    static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+                            const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                            uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
                             uint32_t rotation, sp<GraphicBuffer>* outBuffer);
     static status_t captureLayers(const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index f020a40..ab6dcaa 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -23,6 +23,7 @@
         "IGraphicBufferProducer_test.cpp",
         "Malicious.cpp",
         "MultiTextureConsumer_test.cpp",
+        "RegionSampling_test.cpp",
         "StreamSplitter_test.cpp",
         "SurfaceTextureClient_test.cpp",
         "SurfaceTextureFBO_test.cpp",
@@ -87,3 +88,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/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
new file mode 100644
index 0000000..5652c0c
--- /dev/null
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -0,0 +1,300 @@
+/*
+ * 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 <thread>
+
+#include <binder/ProcessState.h>
+#include <gui/DisplayEventReceiver.h>
+#include <gui/IRegionSamplingListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <utils/Looper.h>
+
+using namespace std::chrono_literals;
+
+namespace android::test {
+
+struct ChoreographerSync {
+    ChoreographerSync(DisplayEventReceiver& receiver) : receiver_(receiver) {}
+    ~ChoreographerSync() = default;
+
+    void notify() const {
+        std::unique_lock<decltype(mutex_)> lk(mutex_);
+
+        auto check_event = [](auto const& ev) -> bool {
+            return ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+        };
+        DisplayEventReceiver::Event ev_;
+        int evs = receiver_.getEvents(&ev_, 1);
+        auto vsync_event_found = check_event(ev_);
+        while (evs) {
+            evs = receiver_.getEvents(&ev_, 1);
+            vsync_event_found |= check_event(ev_);
+        }
+
+        if (vsync_event_found) {
+            notification_arrived_ = true;
+            cv_.notify_all();
+        }
+    }
+
+    void wait_vsync_notify() const {
+        std::unique_lock<decltype(mutex_)> lk(mutex_);
+        cv_.wait(lk, [this] { return notification_arrived_; });
+        notification_arrived_ = false;
+    }
+
+private:
+    ChoreographerSync(ChoreographerSync const&) = delete;
+    ChoreographerSync& operator=(ChoreographerSync const&) = delete;
+
+    std::mutex mutable mutex_;
+    std::condition_variable mutable cv_;
+    bool mutable notification_arrived_ = false;
+    DisplayEventReceiver& receiver_;
+};
+
+struct ChoreographerSim {
+    static std::unique_ptr<ChoreographerSim> make() {
+        auto receiver = std::make_unique<DisplayEventReceiver>();
+        if (!receiver || receiver->initCheck() == NO_INIT) {
+            ALOGE("No display reciever");
+            return nullptr;
+        }
+        return std::unique_ptr<ChoreographerSim>(new ChoreographerSim(std::move(receiver)));
+    }
+
+    ~ChoreographerSim() {
+        poll_ = false;
+        looper->wake();
+        choreographer_thread_.join();
+    }
+
+    void request_render_wait(std::function<void()> const& render_fn) {
+        display_event_receiver_->requestNextVsync();
+        choreographer_.wait_vsync_notify();
+        render_fn();
+
+        // Purpose is to make sure that the content is latched by the time we sample.
+        // Waiting one vsync after queueing could still race with vsync, so wait for two, after
+        // which the content is pretty reliably on screen.
+        display_event_receiver_->requestNextVsync();
+        choreographer_.wait_vsync_notify();
+        display_event_receiver_->requestNextVsync();
+        choreographer_.wait_vsync_notify();
+    }
+
+private:
+    ChoreographerSim(std::unique_ptr<DisplayEventReceiver> receiver)
+          : display_event_receiver_{std::move(receiver)},
+            choreographer_{*display_event_receiver_},
+            looper{new Looper(false)} {
+        choreographer_thread_ = std::thread([this] {
+            auto vsync_notify_fd = display_event_receiver_->getFd();
+            looper->addFd(vsync_notify_fd, 0, Looper::EVENT_INPUT,
+                          [](int /*fd*/, int /*events*/, void* data) -> int {
+                              if (!data) return 0;
+                              reinterpret_cast<ChoreographerSync*>(data)->notify();
+                              return 1;
+                          },
+                          const_cast<void*>(reinterpret_cast<void const*>(&choreographer_)));
+
+            while (poll_) {
+                auto const poll_interval =
+                        std::chrono::duration_cast<std::chrono::milliseconds>(1s).count();
+                auto rc = looper->pollOnce(poll_interval);
+                if ((rc != Looper::POLL_CALLBACK) && (rc != Looper::POLL_WAKE))
+                    ALOGW("Vsync Looper returned: %i\n", rc);
+            }
+        });
+    }
+
+    ChoreographerSim(ChoreographerSim const&) = delete;
+    ChoreographerSim& operator=(ChoreographerSim const&) = delete;
+
+    std::unique_ptr<DisplayEventReceiver> const display_event_receiver_;
+    ChoreographerSync const choreographer_;
+    sp<Looper> looper;
+    std::thread choreographer_thread_;
+    std::atomic<bool> poll_{true};
+};
+
+struct Listener : BnRegionSamplingListener {
+    void onSampleCollected(float medianLuma) override {
+        std::unique_lock<decltype(mutex)> lk(mutex);
+        received = true;
+        mLuma = medianLuma;
+        cv.notify_all();
+    };
+    bool wait_event(std::chrono::milliseconds timeout) {
+        std::unique_lock<decltype(mutex)> lk(mutex);
+        return cv.wait_for(lk, timeout, [this] { return received; });
+    }
+
+    float luma() {
+        std::unique_lock<decltype(mutex)> lk(mutex);
+        return mLuma;
+    }
+
+    void reset() {
+        std::unique_lock<decltype(mutex)> lk(mutex);
+        received = false;
+    }
+
+private:
+    std::condition_variable cv;
+    std::mutex mutex;
+    bool received = false;
+    float mLuma = -0.0f;
+};
+
+// Hoisted to TestSuite setup to avoid flake in test (b/124675919)
+std::unique_ptr<ChoreographerSim> gChoreographerSim = nullptr;
+
+struct RegionSamplingTest : ::testing::Test {
+protected:
+    RegionSamplingTest() { ProcessState::self()->startThreadPool(); }
+
+    static void SetUpTestSuite() {
+        gChoreographerSim = ChoreographerSim::make();
+        ASSERT_NE(gChoreographerSim, nullptr);
+    }
+
+    void SetUp() override {
+        mSurfaceComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mSurfaceComposerClient->initCheck());
+
+        mBackgroundLayer =
+                mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0,
+                                                      0, PIXEL_FORMAT_RGBA_8888,
+                                                      ISurfaceComposerClient::eFXSurfaceColor);
+        uint32_t layerPositionBottom = 0x7E000000;
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mBackgroundLayer, layerPositionBottom)
+                .setPosition(mBackgroundLayer, 100, 100)
+                .setColor(mBackgroundLayer, half3{0.5, 0.5, 0.5})
+                .show(mBackgroundLayer)
+                .apply();
+
+        mContentLayer = mSurfaceComposerClient->createSurface(String8("Content RegionSamplingTest"),
+                                                              300, 300, PIXEL_FORMAT_RGBA_8888, 0);
+
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mContentLayer, layerPositionBottom + 1)
+                .setPosition(mContentLayer, 100, 100)
+                .setColor(mContentLayer, half3{0.5, 0.5, 0.5})
+                .show(mContentLayer)
+                .apply();
+
+        mTopLayer = mSurfaceComposerClient->createSurface(String8("TopLayer RegionSamplingTest"), 0,
+                                                          0, PIXEL_FORMAT_RGBA_8888, 0);
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mTopLayer, layerPositionBottom + 2)
+                .setPosition(mTopLayer, 0, 0)
+                .show(mBackgroundLayer)
+                .apply();
+    }
+
+    void fill_render(uint32_t rgba_value) {
+        auto surface = mContentLayer->getSurface();
+        ANativeWindow_Buffer outBuffer;
+        status_t status = surface->lock(&outBuffer, NULL);
+        ASSERT_EQ(status, android::OK);
+        auto b = reinterpret_cast<uint32_t*>(outBuffer.bits);
+        for (auto i = 0; i < outBuffer.height; i++) {
+            for (auto j = 0; j < outBuffer.width; j++) {
+                b[j] = rgba_value;
+            }
+            b += outBuffer.stride;
+        }
+
+        gChoreographerSim->request_render_wait([&surface] { surface->unlockAndPost(); });
+    }
+
+    sp<SurfaceComposerClient> mSurfaceComposerClient;
+    sp<SurfaceControl> mBackgroundLayer;
+    sp<SurfaceControl> mContentLayer;
+    sp<SurfaceControl> mTopLayer;
+
+    uint32_t const rgba_green = 0xFF00FF00;
+    float const luma_green = 0.7152;
+    uint32_t const rgba_blue = 0xFFFF0000;
+    float const luma_blue = 0.0722;
+    float const error_margin = 0.01;
+    float const luma_gray = 0.50;
+};
+
+TEST_F(RegionSamplingTest, CollectsLuma) {
+    fill_render(rgba_green);
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<Listener> listener = new Listener();
+    const Rect sampleArea{100, 100, 200, 200};
+    composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+
+    EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+    EXPECT_NEAR(listener->luma(), luma_green, error_margin);
+
+    composer->removeRegionSamplingListener(listener);
+}
+
+TEST_F(RegionSamplingTest, CollectsChangingLuma) {
+    fill_render(rgba_green);
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<Listener> listener = new Listener();
+    const Rect sampleArea{100, 100, 200, 200};
+    composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+
+    EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+    EXPECT_NEAR(listener->luma(), luma_green, error_margin);
+
+    listener->reset();
+
+    fill_render(rgba_blue);
+    EXPECT_TRUE(listener->wait_event(300ms))
+            << "timed out waiting for 2nd luma event to be received";
+    EXPECT_NEAR(listener->luma(), luma_blue, error_margin);
+
+    composer->removeRegionSamplingListener(listener);
+}
+
+TEST_F(RegionSamplingTest, CollectsLumaFromTwoRegions) {
+    fill_render(rgba_green);
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<Listener> greenListener = new Listener();
+    const Rect greenSampleArea{100, 100, 200, 200};
+    composer->addRegionSamplingListener(greenSampleArea, mTopLayer->getHandle(), greenListener);
+
+    sp<Listener> grayListener = new Listener();
+    const Rect graySampleArea{500, 100, 600, 200};
+    composer->addRegionSamplingListener(graySampleArea, mTopLayer->getHandle(), grayListener);
+
+    EXPECT_TRUE(grayListener->wait_event(300ms))
+            << "timed out waiting for luma event to be received";
+    EXPECT_NEAR(grayListener->luma(), luma_gray, error_margin);
+    EXPECT_TRUE(greenListener->wait_event(300ms))
+            << "timed out waiting for luma event to be received";
+    EXPECT_NEAR(greenListener->luma(), luma_green, error_margin);
+
+    composer->removeRegionSamplingListener(greenListener);
+    composer->removeRegionSamplingListener(grayListener);
+}
+
+} // namespace android::test
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 f127853..a7599e0 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -615,7 +615,8 @@
                            const ui::Dataspace /*reqDataspace*/,
                            const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/,
                            uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
-                           bool /*useIdentityTransform*/, Rotation /*rotation*/) override {
+                           bool /*useIdentityTransform*/, Rotation /*rotation*/,
+                           bool /*captureSecureLayers*/) override {
         return NO_ERROR;
     }
     virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
@@ -678,6 +679,14 @@
             const sp<IRegionSamplingListener>& /*listener*/) override {
         return NO_ERROR;
     }
+    status_t setAllowedDisplayConfigs(const sp<IBinder>& /*displayToken*/,
+                                      const std::vector<int32_t>& /*allowedConfigs*/) override {
+        return NO_ERROR;
+    }
+    status_t getAllowedDisplayConfigs(const sp<IBinder>& /*displayToken*/,
+                                      std::vector<int32_t>* /*outAllowedConfigs*/) override {
+        return NO_ERROR;
+    }
 
 protected:
     IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 1172864..2d78811 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -28,8 +28,8 @@
         "Keyboard.cpp",
         "KeyCharacterMap.cpp",
         "KeyLayoutMap.cpp",
-        "VirtualKeyMap.cpp",
         "TouchVideoFrame.cpp",
+        "VirtualKeyMap.cpp",
     ],
 
     clang: true,
@@ -43,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/InputTransport.cpp b/libs/input/InputTransport.cpp
index 0f7a1f0..e13b40e 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -59,6 +59,18 @@
 // far into the future.  This time is further bounded by 50% of the last time delta.
 static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS;
 
+/**
+ * System property for enabling / disabling touch resampling.
+ * Resampling extrapolates / interpolates the reported touch event coordinates to better
+ * align them to the VSYNC signal, thus resulting in smoother scrolling performance.
+ * Resampling is not needed (and should be disabled) on hardware that already
+ * has touch events triggered by VSYNC.
+ * Set to "1" to enable resampling (default).
+ * Set to "0" to disable resampling.
+ * Resampling is enabled by default.
+ */
+static const char* PROPERTY_RESAMPLING_ENABLED = "ro.input.resampling";
+
 template<typename T>
 inline static T min(const T& a, const T& b) {
     return a < b ? a : b;
@@ -545,18 +557,7 @@
 }
 
 bool InputConsumer::isTouchResamplingEnabled() {
-    char value[PROPERTY_VALUE_MAX];
-    int length = property_get("ro.input.noresample", value, nullptr);
-    if (length > 0) {
-        if (!strcmp("1", value)) {
-            return false;
-        }
-        if (strcmp("0", value)) {
-            ALOGD("Unrecognized property value for 'ro.input.noresample'.  "
-                    "Use '1' or '0'.");
-        }
-    }
-    return true;
+    return property_get_bool(PROPERTY_RESAMPLING_ENABLED, true);
 }
 
 status_t InputConsumer::consume(InputEventFactoryInterface* factory,
diff --git a/libs/input/TouchVideoFrame.cpp b/libs/input/TouchVideoFrame.cpp
index 35cb4a7..8a4298a 100644
--- a/libs/input/TouchVideoFrame.cpp
+++ b/libs/input/TouchVideoFrame.cpp
@@ -39,4 +39,62 @@
 
 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..ade931e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -3,10 +3,12 @@
     name: "libinput_tests",
     srcs: [
         "InputChannel_test.cpp",
+        "InputDevice_test.cpp",
         "InputEvent_test.cpp",
         "InputPublisherAndConsumer_test.cpp",
+        "InputWindow_test.cpp",
+        "TouchVideoFrame_test.cpp",
         "VelocityTracker_test.cpp",
-        "InputWindow_test.cpp"
     ],
     cflags: [
         "-Wall",
@@ -34,6 +36,7 @@
         "-O0",
         "-Wall",
         "-Werror",
+        "-Wextra",
     ],
     shared_libs: [
         "libinput",
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
new file mode 100644
index 0000000..c174ae9
--- /dev/null
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <input/InputDevice.h>
+
+namespace android {
+
+// --- InputDeviceIdentifierTest ---
+
+TEST(InputDeviceIdentifierTest, getCanonicalName) {
+    InputDeviceIdentifier identifier;
+    identifier.name = "test device";
+    ASSERT_EQ(std::string("test_device"), identifier.getCanonicalName());
+
+    identifier.name = "deviceName-123 version_C!";
+    ASSERT_EQ(std::string("deviceName-123_version_C_"), identifier.getCanonicalName());
+}
+
+} // namespace android
\ No newline at end of file
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/include/android/hdr_metadata.h b/libs/nativewindow/include/android/hdr_metadata.h
index 7e1313b..88772a9 100644
--- a/libs/nativewindow/include/android/hdr_metadata.h
+++ b/libs/nativewindow/include/android/hdr_metadata.h
@@ -33,6 +33,15 @@
  */
 
 /**
+ * HDR metadata standards that are supported by Android.
+ */
+enum AHdrMetadataType : uint32_t {
+    HDR10_SMPTE2086 = 1,
+    HDR10_CTA861_3 = 2,
+    HDR10PLUS_SEI = 3,
+};
+
+/**
  * Color is defined in CIE XYZ coordinates.
  */
 struct AColor_xy {
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/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 6dd7283..166c267 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -24,15 +24,16 @@
 namespace android {
 namespace renderengine {
 
-std::unique_ptr<impl::RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
+std::unique_ptr<impl::RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags,
+                                                         uint32_t imageCacheSize) {
     char prop[PROPERTY_VALUE_MAX];
     property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "gles");
     if (strcmp(prop, "gles") == 0) {
         ALOGD("RenderEngine GLES Backend");
-        return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags);
+        return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags, imageCacheSize);
     }
     ALOGE("UNKNOWN BackendType: %s, create GLES RenderEngine.", prop);
-    return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags);
+    return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags, imageCacheSize);
 }
 
 RenderEngine::~RenderEngine() = default;
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 8f9071e..5d0aa1e 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -37,6 +37,7 @@
 #include <sync/sync.h>
 #include <ui/ColorSpace.h>
 #include <ui/DebugUtils.h>
+#include <ui/GraphicBuffer.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
 #include <utils/KeyedVector.h>
@@ -225,7 +226,8 @@
     return err;
 }
 
-std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(int hwcFormat, uint32_t featureFlags) {
+std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(int hwcFormat, uint32_t featureFlags,
+                                                           uint32_t imageCacheSize) {
     // initialize EGL for the default display
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (!eglInitialize(display, nullptr, nullptr)) {
@@ -295,7 +297,8 @@
         case GLES_VERSION_2_0:
         case GLES_VERSION_3_0:
             engine = std::make_unique<GLESRenderEngine>(featureFlags, display, config, ctxt, dummy,
-                                                        protectedContext, protectedDummy);
+                                                        protectedContext, protectedDummy,
+                                                        imageCacheSize);
             break;
     }
 
@@ -351,7 +354,7 @@
 
 GLESRenderEngine::GLESRenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
                                    EGLContext ctxt, EGLSurface dummy, EGLContext protectedContext,
-                                   EGLSurface protectedDummy)
+                                   EGLSurface protectedDummy, uint32_t imageCacheSize)
       : renderengine::impl::RenderEngine(featureFlags),
         mEGLDisplay(display),
         mEGLConfig(config),
@@ -361,6 +364,7 @@
         mProtectedDummySurface(protectedDummy),
         mVpWidth(0),
         mVpHeight(0),
+        mFramebufferImageCacheSize(imageCacheSize),
         mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
@@ -428,6 +432,10 @@
 }
 
 GLESRenderEngine::~GLESRenderEngine() {
+    for (const auto& image : mFramebufferImageCache) {
+        eglDestroyImageKHR(mEGLDisplay, image.second);
+    }
+    mFramebufferImageCache.clear();
     eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     eglTerminate(mEGLDisplay);
 }
@@ -785,17 +793,48 @@
     }
     return success;
 }
+EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer,
+                                                             bool isProtected) {
+    sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(nativeBuffer);
+    uint32_t bufferId = graphicBuffer->getId();
+    for (const auto& image : mFramebufferImageCache) {
+        if (image.first == bufferId) {
+            return image.second;
+        }
+    }
+    EGLint attributes[] = {
+            isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
+            isProtected ? EGL_TRUE : EGL_NONE,
+            EGL_NONE,
+    };
+    EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                                          nativeBuffer, attributes);
+    if (image != EGL_NO_IMAGE_KHR) {
+        if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) {
+            EGLImageKHR expired = mFramebufferImageCache.front().second;
+            mFramebufferImageCache.pop_front();
+            eglDestroyImageKHR(mEGLDisplay, expired);
+        }
+        mFramebufferImageCache.push_back({bufferId, image});
+    }
+    return image;
+}
 
 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) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 7b72666..e37c91d 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -21,16 +21,17 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <condition_variable>
+#include <deque>
 #include <mutex>
 #include <queue>
 #include <thread>
+#include <unordered_map>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GLES2/gl2.h>
 #include <renderengine/RenderEngine.h>
 #include <renderengine/private/Description.h>
-#include <unordered_map>
 
 #define EGL_NO_CONFIG ((EGLConfig)0)
 
@@ -47,12 +48,14 @@
 
 class GLESRenderEngine : public impl::RenderEngine {
 public:
-    static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags);
+    static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags,
+                                                    uint32_t imageCacheSize);
     static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
 
     GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
                      EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy,
-                     EGLContext protectedContext, EGLSurface protectedDummy);
+                     EGLContext protectedContext, EGLSurface protectedDummy,
+                     uint32_t imageCacheSize);
     ~GLESRenderEngine() override;
 
     std::unique_ptr<Framebuffer> createFramebuffer() override;
@@ -81,11 +84,14 @@
     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; }
+    // Creates an output image for rendering to
+    EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected);
 
 protected:
     Framebuffer* getFramebufferForDrawing() override;
@@ -175,6 +181,12 @@
     // If set to true, then enables tracing flush() and finish() to systrace.
     bool mTraceGpuCompletion = false;
     int32_t mFboHeight = 0;
+    // Maximum size of mFramebufferImageCache. If more images would be cached, then (approximately)
+    // the last recently used buffer should be kicked out.
+    uint32_t mFramebufferImageCacheSize = 0;
+
+    // Cache of output images, keyed by corresponding GraphicBuffer ID.
+    std::deque<std::pair<uint64_t, EGLImageKHR>> mFramebufferImageCache;
 
     // Current dataspace of layer being rendered
     ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index 0e3b405..c45598c 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -30,8 +30,8 @@
 namespace renderengine {
 namespace gl {
 
-GLFramebuffer::GLFramebuffer(const GLESRenderEngine& engine)
-      : mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) {
+GLFramebuffer::GLFramebuffer(GLESRenderEngine& engine)
+      : mEngine(engine), mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) {
     glGenTextures(1, &mTextureName);
     glGenFramebuffers(1, &mFramebufferName);
 }
@@ -39,26 +39,18 @@
 GLFramebuffer::~GLFramebuffer() {
     glDeleteFramebuffers(1, &mFramebufferName);
     glDeleteTextures(1, &mTextureName);
-    eglDestroyImageKHR(mEGLDisplay, mEGLImage);
 }
 
 bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) {
     ATRACE_CALL();
     if (mEGLImage != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(mEGLDisplay, mEGLImage);
         mEGLImage = EGL_NO_IMAGE_KHR;
         mBufferWidth = 0;
         mBufferHeight = 0;
     }
 
     if (nativeBuffer) {
-        EGLint attributes[] = {
-                isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
-                isProtected ? EGL_TRUE : EGL_NONE,
-                EGL_NONE,
-        };
-        mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-                                      nativeBuffer, attributes);
+        mEGLImage = mEngine.createFramebufferImageIfNeeded(nativeBuffer, isProtected);
         if (mEGLImage == EGL_NO_IMAGE_KHR) {
             return false;
         }
diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
index 5043c59..1289fbf 100644
--- a/libs/renderengine/gl/GLFramebuffer.h
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -32,7 +32,7 @@
 
 class GLFramebuffer : public renderengine::Framebuffer {
 public:
-    explicit GLFramebuffer(const GLESRenderEngine& engine);
+    explicit GLFramebuffer(GLESRenderEngine& engine);
     ~GLFramebuffer() override;
 
     bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) override;
@@ -43,6 +43,7 @@
     int32_t getBufferWidth() const { return mBufferWidth; }
 
 private:
+    GLESRenderEngine& mEngine;
     EGLDisplay mEGLDisplay;
     EGLImageKHR mEGLImage;
     uint32_t mTextureName, mFramebufferName;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index b51ed22..2a2b48f 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -65,7 +65,8 @@
         USE_HIGH_PRIORITY_CONTEXT = 1 << 1, // Use high priority context
     };
 
-    static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags);
+    static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags,
+                                                      uint32_t imageCacheSize);
 
     virtual ~RenderEngine() = 0;
 
@@ -167,7 +168,9 @@
     // 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
@@ -176,7 +179,8 @@
     // now, this always returns NO_ERROR.
     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;
 
 protected:
     // Gets a framebuffer to render to. This framebuffer may or may not be
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 800eac3..5956c46 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -78,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 f82beeb..a2bbaff 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) {
@@ -209,7 +210,7 @@
 };
 
 std::unique_ptr<renderengine::RenderEngine> RenderEngineTest::sRE =
-        renderengine::RenderEngine::create(static_cast<int32_t>(ui::PixelFormat::RGBA_8888), 0);
+        renderengine::RenderEngine::create(static_cast<int32_t>(ui::PixelFormat::RGBA_8888), 0, 1);
 
 struct ColorSourceVariant {
     static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index f487dfa..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 {
 
@@ -111,6 +113,7 @@
 
 GraphicBuffer::~GraphicBuffer()
 {
+    ATRACE_CALL();
     if (handle) {
         free_handle();
     }
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 9fa58e2..da9bb49 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -90,6 +90,10 @@
 
 rm src/*.class
 
+# Add UnsupportedAppUsage.java to known sources.
+mkdir -p out/android/annotation
+cp ../../../../base/core/java/android/annotation/UnsupportedAppUsage.java out/android/annotation
+
 pushd out > /dev/null
 mkdir classes
 javac -d classes    android/opengl/EGL14.java \
@@ -109,7 +113,8 @@
                     android/opengl/GLES30.java \
                     android/opengl/GLES31.java \
                     android/opengl/GLES31Ext.java \
-                    android/opengl/GLES32.java
+                    android/opengl/GLES32.java \
+                    android/annotation/UnsupportedAppUsage.java
 popd > /dev/null
 JAVA_RESULT=$?
 if [ $JAVA_RESULT -ne 0 ]; then
@@ -142,7 +147,7 @@
             echo
             SAID_PLEASE=1
         fi
-        echo "    cp $2/$3 $1"
+        echo "    cp $2/$3 $1/$3"
         echo "    (cd $1; git add $3)"
         KEEP_GENERATED=1
     fi
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 6697189..9c80212 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -775,6 +775,19 @@
         }
     }
 
+    String getJniDefaultReturn(JType jType) {
+        if (jType.isPrimitive()) {
+            String baseType = jType.getBaseType();
+            if (baseType.equals("boolean")) {
+                return "JNI_FALSE";
+            } else {
+                return "(" + getJniType(jType) + ")0";
+            }
+        } else {
+            return "nullptr";
+        }
+    }
+
     String getJniMangledName(String name) {
         name = name.replaceAll("_", "_1");
         name = name.replaceAll(";", "_2");
@@ -943,15 +956,15 @@
                         "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
             out.println(indent +
                         "    \"" + cfunc.getName() + "\");");
-            if (!isVoid) {
-                String retval = getErrorReturnValue(cfunc);
+            if (isVoid) {
+                out.println(indent + "return;");
+            } else {
                 if (cfunc.getType().isEGLHandle()) {
                     String baseType = cfunc.getType().getBaseType().toLowerCase();
-                    out.println(indent +
-                                "return toEGLHandle(_env, " + baseType + "Class, " +
-                                baseType + "Constructor, " + retval + ");");
+                    out.println(indent + indent + "return nullptr;");
                 } else {
-                    out.println(indent + "return " + retval + ";");
+                    out.println(indent + indent + "return " +
+                                getJniDefaultReturn(jfunc.getType()) + ";");
                 }
             }
             out.println("}");
@@ -1595,8 +1608,17 @@
             out.println(indent + "if (_exception) {");
             out.println(indent + indent +
                         "jniThrowException(_env, _exceptionType, _exceptionMessage);");
-            out.println(indent + "}");
+            if (!isVoid) {
+                if (cfunc.getType().isEGLHandle()) {
+                    String baseType = cfunc.getType().getBaseType().toLowerCase();
+                    out.println(indent + indent + "return nullptr;");
+                } else {
+                    out.println(indent + indent + "return " +
+                                getJniDefaultReturn(jfunc.getType()) + ";");
+                }
+            }
 
+            out.println(indent + "}");
         }
 
 
diff --git a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
index f3bf220..12728f5 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
@@ -18,6 +18,7 @@
 
 package android.opengl;
 
+import android.annotation.UnsupportedAppUsage;
 import android.graphics.SurfaceTexture;
 import android.view.Surface;
 import android.view.SurfaceView;
diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
index f90e3ec..93203fd 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
@@ -35,8 +35,6 @@
 
 #include <ui/ANativeObjectBase.h>
 
-static int initialized = 0;
-
 static jclass egldisplayClass;
 static jclass eglcontextClass;
 static jclass eglsurfaceClass;
@@ -107,6 +105,7 @@
     if (obj == NULL){
         jniThrowException(_env, "java/lang/IllegalArgumentException",
                           "Object is set to null.");
+        return nullptr;
     }
 
     jlong handle = _env->CallLongMethod(obj, mid);
diff --git a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
index 70b46f7..1c53c9e 100644
--- a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
@@ -14,21 +14,21 @@
 ** limitations under the License.
 */
 
+// This source file is automatically generated
+
 #pragma GCC diagnostic ignored "-Wunused-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
-#include <android_runtime/AndroidRuntime.h>
-#include <nativehelper/JNIHelp.h>
-#include <utils/misc.h>
 #include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
 
-#include <EGL/egl.h>
 #include <assert.h>
+#include <EGL/egl.h>
 
 #include <ui/ANativeObjectBase.h>
 
-static int initialized = 0;
-
 // classes from EGL 1.4
 static jclass egldisplayClass;
 static jclass eglsurfaceClass;
@@ -74,16 +74,18 @@
 
 /* Cache method IDs each time the class is loaded. */
 
-static void nativeClassInit(JNIEnv *_env, jclass glImplClass) {
+static void
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
+{
     // EGL 1.4 Init
     jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
-    eglconfigClass = (jclass)_env->NewGlobalRef(eglconfigClassLocal);
+    eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
     jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext");
-    eglcontextClass = (jclass)_env->NewGlobalRef(eglcontextClassLocal);
+    eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal);
     jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay");
-    egldisplayClass = (jclass)_env->NewGlobalRef(egldisplayClassLocal);
+    egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal);
     jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface");
-    eglsurfaceClass = (jclass)_env->NewGlobalRef(eglsurfaceClassLocal);
+    eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal);
 
     eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
     eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
@@ -95,51 +97,46 @@
     egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
     eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
 
-    jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor,
-                                                      reinterpret_cast<jlong>(EGL_NO_CONTEXT));
+    jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, reinterpret_cast<jlong>(EGL_NO_CONTEXT));
     eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
-    jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor,
-                                                      reinterpret_cast<jlong>(EGL_NO_DISPLAY));
+    jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, reinterpret_cast<jlong>(EGL_NO_DISPLAY));
     eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
-    jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor,
-                                                      reinterpret_cast<jlong>(EGL_NO_SURFACE));
+    jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast<jlong>(EGL_NO_SURFACE));
     eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
 
     jclass eglClass = _env->FindClass("android/opengl/EGL15");
-    jfieldID noContextFieldID =
-            _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
+    jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
     _env->SetStaticObjectField(eglClass, noContextFieldID, eglNoContextObject);
 
-    jfieldID noDisplayFieldID =
-            _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
+    jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
     _env->SetStaticObjectField(eglClass, noDisplayFieldID, eglNoDisplayObject);
 
-    jfieldID noSurfaceFieldID =
-            _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
+    jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
     _env->SetStaticObjectField(eglClass, noSurfaceFieldID, eglNoSurfaceObject);
 
     // EGL 1.5 init
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
-    nioAccessClass = (jclass)_env->NewGlobalRef(nioAccessClassLocal);
+    nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
 
     jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
-    bufferClass = (jclass)_env->NewGlobalRef(bufferClassLocal);
+    bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
 
-    getBasePointerID =
-            _env->GetStaticMethodID(nioAccessClass, "getBasePointer", "(Ljava/nio/Buffer;)J");
-    getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, "getBaseArray",
-                                             "(Ljava/nio/Buffer;)Ljava/lang/Object;");
-    getBaseArrayOffsetID =
-            _env->GetStaticMethodID(nioAccessClass, "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+    getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+            "getBasePointer", "(Ljava/nio/Buffer;)J");
+    getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+            "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+    getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+            "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
 
     positionID = _env->GetFieldID(bufferClass, "position", "I");
     limitID = _env->GetFieldID(bufferClass, "limit", "I");
-    elementSizeShiftID = _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+    elementSizeShiftID =
+        _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
 
     jclass eglimageClassLocal = _env->FindClass("android/opengl/EGLImage");
-    eglimageClass = (jclass)_env->NewGlobalRef(eglimageClassLocal);
+    eglimageClass = (jclass) _env->NewGlobalRef(eglimageClassLocal);
     jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync");
-    eglsyncClass = (jclass)_env->NewGlobalRef(eglsyncClassLocal);
+    eglsyncClass = (jclass) _env->NewGlobalRef(eglsyncClassLocal);
 
     eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
     eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
@@ -147,17 +144,16 @@
     eglimageConstructor = _env->GetMethodID(eglimageClass, "<init>", "(J)V");
     eglsyncConstructor = _env->GetMethodID(eglsyncClass, "<init>", "(J)V");
 
-    jfieldID noImageFieldID =
-            _env->GetStaticFieldID(eglClass, "EGL_NO_IMAGE", "Landroid/opengl/EGLImage;");
+    jfieldID noImageFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_IMAGE", "Landroid/opengl/EGLImage;");
     _env->SetStaticObjectField(eglClass, noImageFieldID, eglNoImageObject);
 
-    jfieldID noSyncFieldID =
-            _env->GetStaticFieldID(eglClass, "EGL_NO_SYNC", "Landroid/opengl/EGLSync;");
+    jfieldID noSyncFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SYNC", "Landroid/opengl/EGLSync;");
     _env->SetStaticObjectField(eglClass, noSyncFieldID, eglNoSyncObject);
 }
 
-static void *getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining,
-                        jint *offset) {
+static void *
+getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset)
+{
     jint position;
     jint limit;
     jint elementSizeShift;
@@ -167,34 +163,42 @@
     limit = _env->GetIntField(buffer, limitID);
     elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
     *remaining = (limit - position) << elementSizeShift;
-    pointer = _env->CallStaticLongMethod(nioAccessClass, getBasePointerID, buffer);
+    pointer = _env->CallStaticLongMethod(nioAccessClass,
+            getBasePointerID, buffer);
     if (pointer != 0L) {
         *array = NULL;
-        return reinterpret_cast<void *>(pointer);
+        return reinterpret_cast<void*>(pointer);
     }
-    eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
-    eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
 
-    *array = (jarray)_env->CallStaticObjectMethod(nioAccessClass, getBaseArrayID, buffer);
-    *offset = _env->CallStaticIntMethod(nioAccessClass, getBaseArrayOffsetID, buffer);
+    *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
+            getBaseArrayID, buffer);
+    *offset = _env->CallStaticIntMethod(nioAccessClass,
+            getBaseArrayOffsetID, buffer);
 
     return NULL;
 }
 
-static void releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) {
-    _env->ReleasePrimitiveArrayCritical(array, data, commit ? 0 : JNI_ABORT);
+static void
+releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
+{
+    _env->ReleasePrimitiveArrayCritical(array, data,
+                       commit ? 0 : JNI_ABORT);
 }
 
-static void *fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
+static void *
+fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
     if (obj == NULL) {
-        jniThrowException(_env, "java/lang/IllegalArgumentException", "Object is set to null.");
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                          "Object is set to null.");
+        return nullptr;
     }
 
     jlong handle = _env->CallLongMethod(obj, mid);
-    return reinterpret_cast<void *>(handle);
+    return reinterpret_cast<void*>(handle);
 }
 
-static jobject toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void *handle) {
+static jobject
+toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void *handle) {
     if (cls == eglimageClass && (EGLImage)handle == EGL_NO_IMAGE) {
         return eglNoImageObject;
     }
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
index 12b96f4..b3b0690 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
@@ -36,8 +36,6 @@
 
 #include <ui/ANativeObjectBase.h>
 
-static int initialized = 0;
-
 static jclass egldisplayClass;
 static jclass eglcontextClass;
 static jclass eglsurfaceClass;
@@ -104,6 +102,7 @@
     if (obj == NULL){
         jniThrowException(_env, "java/lang/IllegalArgumentException",
                           "Object is set to null.");
+        return nullptr;
     }
 
     return reinterpret_cast<void*>(_env->CallLongMethod(obj, mid));
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
index 497d284..f229860 100755
--- a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
@@ -54,6 +54,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
     }
     return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
 }
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp
index 3eacf3c..2e146a8 100644
--- a/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp
@@ -4,6 +4,6 @@
   (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jint pixmap, jintArray attrib_list_ref, jint offset) {
     jniThrowException(_env, "java/lang/UnsupportedOperationException",
         "eglCreatePixmapSurface");
-    return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, (EGLSurface) 0);
+    return nullptr;
 }
 
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
index 355c4b0..7c255ed 100644
--- a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
@@ -67,6 +67,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
     }
     return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
 }
@@ -149,6 +150,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
     }
     return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
 }
diff --git a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
index 7532abf..85f743d 100755
--- a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
+++ b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
@@ -7,6 +7,7 @@
     /**
      * {@hide}
      */
+    @UnsupportedAppUsage
     public static native EGLDisplay eglGetDisplay(
         long display_id
     );
diff --git a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
index fd44498..3a6176f 100644
--- a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
@@ -40,6 +40,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
     }
     return toEGLHandle(_env, egldisplayClass, egldisplayConstructor, _returnValue);
 }
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if b/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
index 9ce6728..c2711aa 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
+++ b/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
@@ -19,6 +19,8 @@
 
 package android.opengl;
 
+import android.annotation.UnsupportedAppUsage;
+
 /** OpenGL ES 2.0
  */
 public class GLES20 {
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index 2163d76..51e62ed 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -4,8 +4,6 @@
 #include <utils/misc.h>
 #include <assert.h>
 
-static int initialized = 0;
-
 static jclass nioAccessClass;
 static jclass bufferClass;
 static jmethodID getBasePointerID;
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java
index d66200f..b297b7a 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java
@@ -17,6 +17,7 @@
     // C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )
 
     /** @hide Method is broken, but used to be public (b/6006380) */
+    @UnsupportedAppUsage
     public static native void glGetActiveAttrib(
         int program,
         int index,
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java
index 8c8d5a2..f211440 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java
@@ -17,6 +17,7 @@
     // C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )
 
     /** @hide Method is broken, but used to be public (b/6006380) */
+    @UnsupportedAppUsage
     public static native void glGetActiveUniform(
         int program,
         int index,
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 29296ff..c808fe9 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -64,8 +64,6 @@
         GLsizei stride, const GLvoid *pointer, GLsizei count);
 }
 
-static int initialized = 0;
-
 static jclass nioAccessClass;
 static jclass bufferClass;
 static jclass G11ImplClass;
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index e21d8e7..dbb6ba6 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -2,6 +2,7 @@
     name: "gpuservice_sources",
     srcs: [
         "GpuService.cpp",
+        "gpustats/GpuStats.cpp"
     ],
 }
 
@@ -29,6 +30,7 @@
         "frameworks/native/vulkan/include",
     ],
     shared_libs: [
+        "libbase",
         "libbinder",
         "libcutils",
         "libgraphicsenv",
@@ -37,6 +39,7 @@
         "libvulkan",
     ],
     static_libs: [
+        "libserviceutils",
         "libvkjson",
     ],
 }
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 81b70c0..a73705b 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -18,45 +18,45 @@
 
 #include "GpuService.h"
 
+#include <android-base/stringprintf.h>
+#include <binder/IPCThreadState.h>
 #include <binder/IResultReceiver.h>
 #include <binder/Parcel.h>
+#include <binder/PermissionCache.h>
+#include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
 #include <utils/String8.h>
 #include <utils/Trace.h>
 
 #include <vkjson.h>
 
+#include "gpustats/GpuStats.h"
+
 namespace android {
 
+using base::StringAppendF;
 
 namespace {
-    status_t cmd_help(int out);
-    status_t cmd_vkjson(int out, int err);
-}
+status_t cmdHelp(int out);
+status_t cmdVkjson(int out, int err);
+void dumpGameDriverInfo(std::string* result);
+} // namespace
+
+const String16 sDump("android.permission.DUMP");
 
 const char* const GpuService::SERVICE_NAME = "gpu";
 
-GpuService::GpuService() = default;
+GpuService::GpuService() : mGpuStats(std::make_unique<GpuStats>()){};
 
 void GpuService::setGpuStats(const std::string& driverPackageName,
                              const std::string& driverVersionName, uint64_t driverVersionCode,
-                             const std::string& driverBuildDate, const std::string& appPackageName,
+                             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[%llu]\n"
-          "\tdriverBuildDate[%s]\n"
-          "\tappPackageName[%s]\n"
-          "\tdriver[%d]\n"
-          "\tisDriverLoaded[%d]\n"
-          "\tdriverLoadingTime[%lld]",
-          driverPackageName.c_str(), driverVersionName.c_str(),
-          (unsigned long long)driverVersionCode, driverBuildDate.c_str(), appPackageName.c_str(),
-          static_cast<int32_t>(driver), isDriverLoaded, (long long)driverLoadingTime);
+    mGpuStats->insert(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
+                      appPackageName, driver, isDriverLoaded, driverLoadingTime);
 }
 
 status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) {
@@ -67,28 +67,60 @@
         ALOGV("  arg[%zu]: '%s'", i, String8(args[i]).string());
 
     if (args.size() >= 1) {
-        if (args[0] == String16("vkjson"))
-            return cmd_vkjson(out, err);
-        if (args[0] == String16("help"))
-            return cmd_help(out);
+        if (args[0] == String16("vkjson")) return cmdVkjson(out, err);
+        if (args[0] == String16("help")) return cmdHelp(out);
     }
     // no command, or unrecognized command
-    cmd_help(err);
+    cmdHelp(err);
     return BAD_VALUE;
 }
 
+status_t GpuService::doDump(int fd, const Vector<String16>& args, bool /*asProto*/) {
+    std::string result;
+
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+
+    if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) {
+        StringAppendF(&result, "Permission Denial: can't dump gpu from pid=%d, uid=%d\n", pid, uid);
+    } else {
+        bool dumpAll = true;
+        size_t index = 0;
+        size_t numArgs = args.size();
+
+        if (numArgs) {
+            if ((index < numArgs) && (args[index] == String16("--gpustats"))) {
+                index++;
+                mGpuStats->dump(args, &result);
+                dumpAll = false;
+            }
+        }
+
+        if (dumpAll) {
+            dumpGameDriverInfo(&result);
+            result.append("\n");
+
+            mGpuStats->dump(Vector<String16>(), &result);
+            result.append("\n");
+        }
+    }
+
+    write(fd, result.c_str(), result.size());
+    return NO_ERROR;
+}
+
 namespace {
 
-status_t cmd_help(int out) {
+status_t cmdHelp(int out) {
     FILE* outs = fdopen(out, "w");
     if (!outs) {
-        ALOGE("vkjson: failed to create out stream: %s (%d)", strerror(errno),
-            errno);
+        ALOGE("vkjson: failed to create out stream: %s (%d)", strerror(errno), errno);
         return BAD_VALUE;
     }
     fprintf(outs,
-        "GPU Service commands:\n"
-        "  vkjson   dump Vulkan properties as JSON\n");
+            "GPU Service commands:\n"
+            "  vkjson   dump Vulkan properties as JSON\n");
     fclose(outs);
     return NO_ERROR;
 }
@@ -99,7 +131,7 @@
     fputc('\n', out);
 }
 
-status_t cmd_vkjson(int out, int /*err*/) {
+status_t cmdVkjson(int out, int /*err*/) {
     FILE* outs = fdopen(out, "w");
     if (!outs) {
         int errnum = errno;
@@ -111,6 +143,18 @@
     return NO_ERROR;
 }
 
+void dumpGameDriverInfo(std::string* result) {
+    if (!result) return;
+
+    char stableGameDriver[PROPERTY_VALUE_MAX] = {};
+    property_get("ro.gfx.driver.0", stableGameDriver, "unsupported");
+    StringAppendF(result, "Stable Game Driver: %s\n", stableGameDriver);
+
+    char preReleaseGameDriver[PROPERTY_VALUE_MAX] = {};
+    property_get("ro.gfx.driver.1", preReleaseGameDriver, "unsupported");
+    StringAppendF(result, "Pre-release Game Driver: %s\n", preReleaseGameDriver);
+}
+
 } // anonymous namespace
 
 } // namespace android
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 76234a3..0cf48bb 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -20,13 +20,16 @@
 #include <binder/IInterface.h>
 #include <cutils/compiler.h>
 #include <graphicsenv/IGpuService.h>
+#include <serviceutils/PriorityDumper.h>
 
 #include <mutex>
 #include <vector>
 
 namespace android {
 
-class GpuService : public BnGpuService {
+class GpuStats;
+
+class GpuService : public BnGpuService, public PriorityDumper {
 public:
     static const char* const SERVICE_NAME ANDROID_API;
 
@@ -36,14 +39,36 @@
     status_t shellCommand(int in, int out, int err, std::vector<String16>& args) override;
 
 private:
-    // IGpuService interface
+    /*
+     * IGpuService interface
+     */
     void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
-                     uint64_t driverVersionCode, const std::string& driverBuildDate,
+                     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;
+    /*
+     * IBinder interface
+     */
+    status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); }
+
+    /*
+     * Debugging & dumpsys
+     */
+    status_t dumpCritical(int fd, const Vector<String16>& /*args*/, bool asProto) override {
+        return doDump(fd, Vector<String16>(), asProto);
+    }
+
+    status_t dumpAll(int fd, const Vector<String16>& args, bool asProto) override {
+        return doDump(fd, args, asProto);
+    }
+
+    status_t doDump(int fd, const Vector<String16>& args, bool asProto);
+
+    /*
+     * Attributes
+     */
+    std::unique_ptr<GpuStats> mGpuStats;
 };
 
 } // namespace android
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
new file mode 100644
index 0000000..43c9492
--- /dev/null
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+#undef LOG_TAG
+#define LOG_TAG "GpuStats"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "GpuStats.h"
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+#include <unordered_set>
+
+namespace android {
+
+using base::StringAppendF;
+
+static bool addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded,
+                            GpuStatsGlobalAtom* const outGlobalAtom) {
+    switch (driver) {
+        case GraphicsEnv::Driver::GL:
+        case GraphicsEnv::Driver::GL_UPDATED:
+            outGlobalAtom->glLoadingCount++;
+            if (!isDriverLoaded) outGlobalAtom->glLoadingFailureCount++;
+            break;
+        case GraphicsEnv::Driver::VULKAN:
+        case GraphicsEnv::Driver::VULKAN_UPDATED:
+            outGlobalAtom->vkLoadingCount++;
+            if (!isDriverLoaded) outGlobalAtom->vkLoadingFailureCount++;
+            break;
+        default:
+            // Currently we don't support GraphicsEnv::Driver::ANGLE because the
+            // basic driver package info only belongs to system or updated driver.
+            return false;
+    }
+
+    return true;
+}
+
+static void addLoadingTime(GraphicsEnv::Driver driver, int64_t driverLoadingTime,
+                           GpuStatsAppAtom* const outAppAtom) {
+    switch (driver) {
+        case GraphicsEnv::Driver::GL:
+        case GraphicsEnv::Driver::GL_UPDATED:
+            outAppAtom->glDriverLoadingTime.emplace_back(driverLoadingTime);
+            break;
+        case GraphicsEnv::Driver::VULKAN:
+        case GraphicsEnv::Driver::VULKAN_UPDATED:
+            outAppAtom->vkDriverLoadingTime.emplace_back(driverLoadingTime);
+            break;
+        default:
+            break;
+    }
+}
+
+void GpuStats::insert(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(mLock);
+    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);
+
+    if (!mGlobalStats.count(driverVersionCode)) {
+        GpuStatsGlobalAtom globalAtom;
+        if (!addLoadingCount(driver, isDriverLoaded, &globalAtom)) {
+            return;
+        }
+        globalAtom.driverPackageName = driverPackageName;
+        globalAtom.driverVersionName = driverVersionName;
+        globalAtom.driverVersionCode = driverVersionCode;
+        globalAtom.driverBuildTime = driverBuildTime;
+        mGlobalStats.insert({driverVersionCode, globalAtom});
+    } else if (!addLoadingCount(driver, isDriverLoaded, &mGlobalStats[driverVersionCode])) {
+        return;
+    }
+
+    if (mAppStats.size() >= MAX_NUM_APP_RECORDS) {
+        ALOGV("GpuStatsAppAtom has reached maximum size. Ignore new stats.");
+        return;
+    }
+
+    const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode);
+    if (!mAppStats.count(appStatsKey)) {
+        GpuStatsAppAtom appAtom;
+        addLoadingTime(driver, driverLoadingTime, &appAtom);
+        appAtom.appPackageName = appPackageName;
+        appAtom.driverVersionCode = driverVersionCode;
+        mAppStats.insert({appStatsKey, appAtom});
+        return;
+    }
+
+    addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
+}
+
+void GpuStats::dump(const Vector<String16>& args, std::string* result) {
+    ATRACE_CALL();
+
+    if (!result) {
+        ALOGE("Dump result shouldn't be nullptr.");
+        return;
+    }
+
+    std::lock_guard<std::mutex> lock(mLock);
+    bool dumpAll = true;
+
+    std::unordered_set<std::string> argsSet;
+    for (size_t i = 0; i < args.size(); i++) {
+        argsSet.insert(String8(args[i]).c_str());
+    }
+
+    const bool dumpGlobal = argsSet.count("--global") != 0;
+    if (dumpGlobal) {
+        dumpGlobalLocked(result);
+        dumpAll = false;
+    }
+
+    const bool dumpApp = argsSet.count("--app") != 0;
+    if (dumpApp) {
+        dumpAppLocked(result);
+        dumpAll = false;
+    }
+
+    if (argsSet.count("--clear")) {
+        bool clearAll = true;
+
+        if (dumpGlobal) {
+            mGlobalStats.clear();
+            clearAll = false;
+        }
+
+        if (dumpApp) {
+            mAppStats.clear();
+            clearAll = false;
+        }
+
+        if (clearAll) {
+            mGlobalStats.clear();
+            mAppStats.clear();
+        }
+
+        dumpAll = false;
+    }
+
+    if (dumpAll) {
+        dumpGlobalLocked(result);
+        dumpAppLocked(result);
+    }
+}
+
+void GpuStats::dumpGlobalLocked(std::string* result) {
+    result->append("GpuStats global:\n");
+
+    for (const auto& ele : mGlobalStats) {
+        StringAppendF(result, "  driverPackageName = %s\n", ele.second.driverPackageName.c_str());
+        StringAppendF(result, "  driverVersionName = %s\n", ele.second.driverVersionName.c_str());
+        StringAppendF(result, "  driverVersionCode = %" PRIu64 "\n", ele.second.driverVersionCode);
+        StringAppendF(result, "  driverBuildTime = %" PRId64 "\n", ele.second.driverBuildTime);
+        StringAppendF(result, "  glLoadingCount = %d\n", ele.second.glLoadingCount);
+        StringAppendF(result, "  glLoadingFailureCount = %d\n", ele.second.glLoadingFailureCount);
+        StringAppendF(result, "  vkLoadingCount = %d\n", ele.second.vkLoadingCount);
+        StringAppendF(result, "  vkLoadingFailureCount = %d\n", ele.second.vkLoadingFailureCount);
+        result->append("\n");
+    }
+}
+
+void GpuStats::dumpAppLocked(std::string* result) {
+    result->append("GpuStats app:\n");
+
+    for (const auto& ele : mAppStats) {
+        StringAppendF(result, "  appPackageName = %s\n", ele.second.appPackageName.c_str());
+        StringAppendF(result, "  driverVersionCode = %" PRIu64 "\n", ele.second.driverVersionCode);
+
+        result->append("  glDriverLoadingTime:");
+        for (int32_t loadingTime : ele.second.glDriverLoadingTime) {
+            StringAppendF(result, " %d", loadingTime);
+        }
+        result->append("\n");
+
+        result->append("  vkDriverLoadingTime:");
+        for (int32_t loadingTime : ele.second.vkDriverLoadingTime) {
+            StringAppendF(result, " %d", loadingTime);
+        }
+        result->append("\n\n");
+    }
+}
+
+} // namespace android
diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h
new file mode 100644
index 0000000..8837c39
--- /dev/null
+++ b/services/gpuservice/gpustats/GpuStats.h
@@ -0,0 +1,60 @@
+/*
+ * 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 <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <graphicsenv/GpuStatsAtoms.h>
+#include <graphicsenv/GraphicsEnv.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class GpuStats {
+public:
+    GpuStats() = default;
+    ~GpuStats() = default;
+
+    // Insert new gpu stats into global stats and app stats.
+    void insert(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);
+    // dumpsys interface
+    void dump(const Vector<String16>& args, std::string* result);
+
+private:
+    // Dump global stats
+    void dumpGlobalLocked(std::string* result);
+    // Dump app stats
+    void dumpAppLocked(std::string* result);
+
+    // This limits the memory usage of GpuStats to be less than 30KB. This is
+    // the maximum atom size statsd could afford.
+    static const size_t MAX_NUM_APP_RECORDS = 300;
+    // GpuStats access should be guarded by mLock.
+    std::mutex mLock;
+    // Key is driver version code.
+    std::unordered_map<uint64_t, GpuStatsGlobalAtom> mGlobalStats;
+    // Key is <app package name>+<driver version code>.
+    std::unordered_map<std::string, GpuStatsAppAtom> mAppStats;
+};
+
+} // 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 c9eb683..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());
     }
@@ -91,7 +98,7 @@
     }
 
 private:
-    size_t mCapacity;
+    const size_t mCapacity;
     /**
      * Used to signal that mQueue is non-empty.
      */
@@ -100,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 c13bac6..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() {
@@ -1364,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;
         }
     }
@@ -1614,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/EventHub.h b/services/inputflinger/EventHub.h
index d176648..44f7b37 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -345,7 +345,7 @@
 
         std::string configurationFile;
         PropertyMap* configuration;
-        VirtualKeyMap* virtualKeyMap;
+        std::unique_ptr<VirtualKeyMap> virtualKeyMap;
         KeyMap keyMap;
 
         sp<KeyCharacterMap> overlayKeyMap;
@@ -416,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.h b/services/inputflinger/InputClassifier.h
index 4b9dae2..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>
@@ -151,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.
      */
@@ -161,7 +162,7 @@
      */
     MotionClassification getClassification(int32_t deviceId);
     void updateClassification(int32_t deviceId, nsecs_t eventTime,
-        MotionClassification classification);
+            MotionClassification classification);
     /**
      * Clear all current classifications
      */
@@ -172,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);
 
     /**
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 7ff8b20..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;
             }
@@ -2994,7 +2992,7 @@
     }
 }
 
-void InputDispatcher::incrementPendingForegroundDispatchesLocked(EventEntry* entry) {
+void InputDispatcher::incrementPendingForegroundDispatches(EventEntry* entry) {
     InjectionState* injectionState = entry->injectionState;
     if (injectionState) {
         injectionState->pendingForegroundDispatches += 1;
@@ -3014,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;
     }
@@ -3038,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();
@@ -3075,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
@@ -3225,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(
@@ -3884,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.
@@ -3897,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);
@@ -3911,7 +3912,7 @@
     commandEntry->reason = reason;
 }
 
-void InputDispatcher::doNotifyConfigurationChangedInterruptible(
+void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible (
         CommandEntry* commandEntry) {
     mLock.unlock();
 
@@ -4027,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);
             }
@@ -4242,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.
 }
@@ -4253,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());
@@ -4261,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 595b01d..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 {
 
 /*
@@ -315,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.
      *
@@ -406,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);
@@ -888,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;
@@ -946,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 {
@@ -970,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 {
@@ -1037,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 {
@@ -1073,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/InputManager.cpp b/services/inputflinger/InputManager.cpp
index a7fd9ba..b0157a1 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -103,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;
@@ -112,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 e632da3..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>
@@ -93,7 +94,8 @@
     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 1a1ae21..21ba029 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -6565,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/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/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index fbacb9b..80a55f1 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -335,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() {
@@ -499,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).";
@@ -614,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 {};
     }
 
@@ -6415,4 +6427,78 @@
     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/AllowedDisplayConfigs.h b/services/surfaceflinger/AllowedDisplayConfigs.h
new file mode 100644
index 0000000..7ca62ea
--- /dev/null
+++ b/services/surfaceflinger/AllowedDisplayConfigs.h
@@ -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.
+ */
+
+#pragma once
+
+#include <log/log.h>
+#include <vector>
+
+/*
+ * Used to represent the Display Configurations allowed to be set by SurfaceFlinger
+ */
+class AllowedDisplayConfigs {
+private:
+    // Defining ConstructorTag as private to prevent instantiating this class from outside
+    // while still allowing it to be constructed by std::make_unique
+    struct ConstructorTag {};
+
+public:
+    AllowedDisplayConfigs(ConstructorTag) {}
+
+    class Builder {
+    public:
+        Builder()
+              : mAllowedDisplayConfigs(std::make_unique<AllowedDisplayConfigs>(ConstructorTag{})) {}
+
+        std::unique_ptr<const AllowedDisplayConfigs> build() {
+            return std::move(mAllowedDisplayConfigs);
+        }
+
+        // add a config to the allowed config set
+        Builder& addConfig(int32_t config) {
+            mAllowedDisplayConfigs->addConfig(config);
+            return *this;
+        }
+
+    private:
+        std::unique_ptr<AllowedDisplayConfigs> mAllowedDisplayConfigs;
+    };
+
+    bool isConfigAllowed(int32_t config) const {
+        return (std::find(mConfigs.begin(), mConfigs.end(), config) != mConfigs.end());
+    }
+
+    void getAllowedConfigs(std::vector<int32_t>* outConfigs) const {
+        if (outConfigs) {
+            *outConfigs = mConfigs;
+        }
+    }
+
+private:
+    // add a config to the allowed config set
+    void addConfig(int32_t config) { mConfigs.push_back(config); }
+
+    std::vector<int32_t> mConfigs;
+};
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 734ed6c..9bf499b 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -134,7 +134,6 @@
         "EventLog/EventLog.cpp",
         "FrameTracker.cpp",
         "Layer.cpp",
-        "LayerBE.cpp",
         "LayerProtoHelper.cpp",
         "LayerRejecter.cpp",
         "LayerStats.cpp",
@@ -142,6 +141,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 b4952aa..6badc73 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -69,13 +69,6 @@
 
 BufferLayer::~BufferLayer() {
     mFlinger->deleteTextureAsync(mTextureName);
-
-    if (destroyAllHwcLayersPlusChildren()) {
-        ALOGE("Found stale hardware composer layers when destroying "
-              "surface flinger layer %s",
-              mName.string());
-    }
-
     mFlinger->mTimeStats->onDestroy(getSequence());
 }
 
@@ -132,9 +125,11 @@
 
 bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                                      bool useIdentityTransform, Region& clearRegion,
+                                     const bool supportProtectedContent,
                                      renderengine::LayerSettings& layer) {
     ATRACE_CALL();
-    Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, layer);
+    Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
+                              supportProtectedContent, 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
@@ -161,7 +156,8 @@
         }
         return false;
     }
-    bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure());
+    bool blackOutLayer =
+            (isProtected() && !supportProtectedContent) || (isSecure() && !renderArea.isSecure());
     const State& s(getDrawingState());
     if (!blackOutLayer) {
         layer.source.buffer.buffer = mActiveBuffer;
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index e3b10fc..c48146f 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -168,7 +168,8 @@
     // prepareClientLayer - constructs a RenderEngine layer for GPU composition.
     bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                             bool useIdentityTransform, Region& clearRegion,
-                            renderengine::LayerSettings& layer);
+                            const bool supportProtectedContent,
+                            renderengine::LayerSettings& layer) override;
 
 private:
     // Returns true if this layer requires filtering
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index b3e2a4b..215dea1 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -199,7 +199,6 @@
     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
         auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
         layerCompositionState.sidebandStream = mConsumer->getSidebandStream();
         if (layerCompositionState.sidebandStream != nullptr) {
@@ -397,9 +396,11 @@
 void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
     // Add this buffer from our internal queue tracker
     { // Autolock scope
-        // Report the requested present time to the Scheduler.
-        mFlinger->mScheduler->addFramePresentTimeForLayer(item.mTimestamp, item.mIsAutoTimestamp,
-                                                          mName.c_str());
+        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());
+        }
 
         Mutex::Autolock lock(mQueueItemLock);
         // Reset the frame number tracker when we receive the first buffer after
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e48c41e..f6b69eb 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -198,7 +198,6 @@
         mReleasePreviousBuffer = true;
     }
 
-    mCurrentState.sequence++;
     mCurrentState.buffer = buffer;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -217,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);
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 9ea0a46..2aeece7 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -50,8 +50,10 @@
 
 bool ColorLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                                     bool useIdentityTransform, Region& clearRegion,
+                                    const bool supportProtectedContent,
                                     renderengine::LayerSettings& layer) {
-    Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, layer);
+    Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
+                              supportProtectedContent, layer);
     half4 color(getColor());
     half3 solidColor(color.r, color.g, color.b);
     layer.source.solidColor = solidColor;
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index df0adac..9786419 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -42,9 +42,10 @@
 
 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);
+    bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+                            bool useIdentityTransform, Region& clearRegion,
+                            const bool supportProtectedContent,
+                            renderengine::LayerSettings& layer) override;
 
 private:
     std::shared_ptr<compositionengine::Layer> mCompositionLayer;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index f9a3624..6cc87ba 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -18,10 +18,19 @@
 
 #include <utils/RefBase.h>
 
-namespace android::compositionengine {
+namespace android {
+
+class Fence;
+
+namespace compositionengine {
 
 // Defines the interface used by the CompositionEngine to make requests
 // of the front-end layer
-class LayerFE : public virtual RefBase {};
+class LayerFE : public virtual RefBase {
+public:
+    // Called after the layer is displayed to update the presentation fence
+    virtual void onLayerDisplayed(const sp<Fence>&) = 0;
+};
 
-} // namespace android::compositionengine
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 2201bdd..785a6d7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -36,6 +36,10 @@
  * 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
      */
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 84b2423..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;
@@ -117,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 48cb581..e7a17c4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -16,14 +16,18 @@
 
 #pragma once
 
+#include <optional>
 #include <string>
 
 #include <utils/StrongPointer.h>
 
+#include "DisplayHardware/DisplayIdentification.h"
+
 namespace android {
 
 namespace compositionengine {
 
+class CompositionEngine;
 class Output;
 class Layer;
 class LayerFE;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index 2009380..e69b99f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -71,7 +71,7 @@
     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. readyFence is the fence
     // which will fire when the buffer is ready for consumption.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 3fd057c..b1d1f42 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -67,7 +67,8 @@
     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 5798540..d8f0cdd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -22,6 +22,8 @@
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
 
+#include "DisplayHardware/DisplayIdentification.h"
+
 namespace android::compositionengine::impl {
 
 class OutputLayer : public compositionengine::OutputLayer {
@@ -30,6 +32,8 @@
                 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;
@@ -48,7 +52,7 @@
 };
 
 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/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 58b13ed..3c79084 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -52,7 +52,7 @@
     void setProtected(bool useProtected) override;
     status_t beginFrame(bool mustRecompose) override;
     status_t prepareFrame() override;
-    sp<GraphicBuffer> dequeueBuffer() override;
+    sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override;
     void queueBuffer(base::unique_fd&& readyFence) override;
     void onPresentDisplayCompleted() override;
     void setViewportAndProjection() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 92e0070..a0c2a63 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -18,6 +18,7 @@
 
 #include <compositionengine/LayerFE.h>
 #include <gmock/gmock.h>
+#include <ui/Fence.h>
 
 namespace android::compositionengine::mock {
 
@@ -27,6 +28,8 @@
 public:
     LayerFE();
     virtual ~LayerFE();
+
+    MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
 };
 
 } // 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 2972ad7..d0e7b19 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -61,9 +61,9 @@
 
     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 6bd61ee..54c7407 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <compositionengine/CompositionEngine.h>
 #include <compositionengine/Layer.h>
 #include <compositionengine/LayerFE.h>
 #include <compositionengine/Output.h>
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index 8442bef..1562f58 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -37,7 +37,7 @@
     MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
     MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
     MOCK_METHOD0(prepareFrame, status_t());
-    MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>());
+    MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*));
     MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
     MOCK_METHOD0(onPresentDisplayCompleted, void());
     MOCK_METHOD0(setViewportAndProjection, void());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index f97add4..ad4c7bf 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -217,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 78c1403..10da49d 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -15,11 +15,14 @@
  */
 
 #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;
@@ -27,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)
@@ -37,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;
 }
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index ebb1bc2..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"
 
@@ -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,13 +149,7 @@
              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;
 }
@@ -172,7 +170,8 @@
             // 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) {
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 cb71821..a84af3a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -338,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());
@@ -354,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 0a7c462..84af9b9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -358,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());
 }
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 22c40d7..738f4b6 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -26,7 +26,7 @@
 
 ContainerLayer::~ContainerLayer() = default;
 
-bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&,
+bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&, const bool,
                                         renderengine::LayerSettings&) {
     return false;
 }
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index c69997d..c7cfdcd 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -43,7 +43,8 @@
 protected:
     bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                             bool useIdentityTransform, Region& clearRegion,
-                            renderengine::LayerSettings& layer);
+                            const bool supportProtectedContent,
+                            renderengine::LayerSettings& layer) override;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index a827c47..c80925e 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -255,17 +255,18 @@
                               device->getCompositionDataSpace(), rotation) {}
     DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqWidth,
                       uint32_t reqHeight, ui::Dataspace reqDataSpace,
-                      ui::Transform::orientation_flags rotation)
+                      ui::Transform::orientation_flags rotation, bool allowSecureLayers = true)
           : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace,
                        getDisplayRotation(rotation, device->getInstallOrientation())),
             mDevice(device),
-            mSourceCrop(sourceCrop) {}
+            mSourceCrop(sourceCrop),
+            mAllowSecureLayers(allowSecureLayers) {}
 
     const ui::Transform& getTransform() const override { return mDevice->getTransform(); }
     Rect getBounds() const override { return mDevice->getBounds(); }
     int getHeight() const override { return mDevice->getHeight(); }
     int getWidth() const override { return mDevice->getWidth(); }
-    bool isSecure() const override { return mDevice->isSecure(); }
+    bool isSecure() const override { return mAllowSecureLayers && mDevice->isSecure(); }
     const sp<const DisplayDevice> getDisplayDevice() const override { return mDevice; }
 
     bool needsFiltering() const override {
@@ -356,6 +357,7 @@
 
     const sp<const DisplayDevice> mDevice;
     const Rect mSourceCrop;
+    const bool mAllowSecureLayers;
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7b8ad71..a6adeb3 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -69,10 +69,7 @@
 std::atomic<int32_t> Layer::sSequence{1};
 
 Layer::Layer(const LayerCreationArgs& args)
-      : mFlinger(args.flinger),
-        mName(args.name),
-        mClientRef(args.client),
-        mBE{this, args.name.string()} {
+      : mFlinger(args.flinger), mName(args.name), mClientRef(args.client) {
     mCurrentCrop.makeInvalid();
 
     uint32_t layerFlags = 0;
@@ -126,8 +123,6 @@
 
     mFrameTracker.logAndResetStats(mName);
 
-    destroyAllHwcLayersPlusChildren();
-
     mFlinger->onLayerDestroyed();
 }
 
@@ -209,61 +204,6 @@
 // h/w composer set-up
 // ---------------------------------------------------------------------------
 
-bool Layer::createHwcLayer(HWComposer* hwc, const sp<DisplayDevice>& displayDevice) {
-    LOG_ALWAYS_FATAL_IF(!displayDevice->getId());
-    auto displayId = *displayDevice->getId();
-    auto outputLayer = findOutputLayerForDisplay(displayDevice);
-    LOG_ALWAYS_FATAL_IF(!outputLayer);
-
-    LOG_ALWAYS_FATAL_IF(outputLayer->getState().hwc.has_value(),
-                        "Already have a layer for display %s",
-                        displayDevice->getDisplayName().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;
-    }
-    auto& state = outputLayer->editState();
-    state.hwc.emplace(layer);
-    return true;
-}
-
-bool Layer::destroyHwcLayer(const sp<DisplayDevice>& displayDevice) {
-    auto outputLayer = findOutputLayerForDisplay(displayDevice);
-    if (outputLayer == nullptr) {
-        return false;
-    }
-    auto& state = outputLayer->editState();
-    bool result = state.hwc.has_value();
-    state.hwc.reset();
-    return result;
-}
-
-bool Layer::destroyHwcLayersForAllDisplays() {
-    bool destroyedAnyLayers = false;
-
-    for (const auto& [token, displayDevice] : mFlinger->mDisplays) {
-        if (destroyHwcLayer(displayDevice)) {
-            destroyedAnyLayers = true;
-        }
-    }
-
-    return destroyedAnyLayers;
-}
-
-bool Layer::destroyAllHwcLayersPlusChildren() {
-    bool result = destroyHwcLayersForAllDisplays();
-
-    for (const sp<Layer>& child : mDrawingChildren) {
-        result |= child->destroyAllHwcLayersPlusChildren();
-    }
-
-    return result;
-}
-
 bool Layer::hasHwcLayer(const sp<const DisplayDevice>& displayDevice) {
     auto outputLayer = findOutputLayerForDisplay(displayDevice);
     LOG_FATAL_IF(!outputLayer);
@@ -740,18 +680,21 @@
 // ---------------------------------------------------------------------------
 
 bool Layer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
-                               Region& clearRegion, renderengine::LayerSettings& layer) {
-    return prepareClientLayer(renderArea, clip, false, clearRegion, layer);
+                               Region& clearRegion, const bool supportProtectedContent,
+                               renderengine::LayerSettings& layer) {
+    return prepareClientLayer(renderArea, clip, false, clearRegion, supportProtectedContent, layer);
 }
 
 bool Layer::prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
-                               Region& clearRegion, renderengine::LayerSettings& layer) {
+                               Region& clearRegion, const bool supportProtectedContent,
+                               renderengine::LayerSettings& layer) {
     return prepareClientLayer(renderArea, Region(renderArea.getBounds()), useIdentityTransform,
-                              clearRegion, layer);
+                              clearRegion, supportProtectedContent, layer);
 }
 
 bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/,
                                bool useIdentityTransform, Region& /*clearRegion*/,
+                               const bool /*supportProtectedContent*/,
                                renderengine::LayerSettings& layer) {
     FloatRect bounds = getBounds();
     half alpha = getAlpha();
@@ -1395,10 +1338,8 @@
     return true;
 }
 
-bool Layer::setMetadata(LayerMetadata data) {
-    bool changed = data.mMap != mCurrentState.metadata.mMap;
-    if (!changed) return false;
-    mCurrentState.metadata = std::move(data);
+bool Layer::setMetadata(const LayerMetadata& data) {
+    if (!mCurrentState.metadata.merge(data, true /* eraseEmpty */)) return false;
     mCurrentState.sequence++;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -2099,26 +2040,26 @@
     }
 
     LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
-                                   layerInfo->mutable_transparent_region());
-    LayerProtoHelper::writeToProto(visibleRegion, layerInfo->mutable_visible_region());
-    LayerProtoHelper::writeToProto(surfaceDamageRegion, layerInfo->mutable_damage_region());
+                                   [&]() { return layerInfo->mutable_transparent_region(); });
+    LayerProtoHelper::writeToProto(visibleRegion,
+                                   [&]() { return layerInfo->mutable_visible_region(); });
+    LayerProtoHelper::writeToProto(surfaceDamageRegion,
+                                   [&]() { return layerInfo->mutable_damage_region(); });
 
     layerInfo->set_layer_stack(getLayerStack());
     layerInfo->set_z(state.z);
 
-    PositionProto* position = layerInfo->mutable_position();
-    position->set_x(transform.tx());
-    position->set_y(transform.ty());
+    LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
+                                           [&]() { return layerInfo->mutable_position(); });
 
-    PositionProto* requestedPosition = layerInfo->mutable_requested_position();
-    requestedPosition->set_x(requestedTransform.tx());
-    requestedPosition->set_y(requestedTransform.ty());
+    LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() {
+        return layerInfo->mutable_requested_position();
+    });
 
-    SizeProto* size = layerInfo->mutable_size();
-    size->set_w(state.active_legacy.w);
-    size->set_h(state.active_legacy.h);
+    LayerProtoHelper::writeSizeToProto(state.active_legacy.w, state.active_legacy.h,
+                                       [&]() { return layerInfo->mutable_size(); });
 
-    LayerProtoHelper::writeToProto(state.crop_legacy, layerInfo->mutable_crop());
+    LayerProtoHelper::writeToProto(state.crop_legacy, [&]() { return layerInfo->mutable_crop(); });
     layerInfo->set_corner_radius(getRoundedCornerState().radius);
 
     layerInfo->set_is_opaque(isOpaque(state));
@@ -2128,8 +2069,9 @@
     layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
 
     layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
-    LayerProtoHelper::writeToProto(getColor(), layerInfo->mutable_color());
-    LayerProtoHelper::writeToProto(state.color, layerInfo->mutable_requested_color());
+    LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
+    LayerProtoHelper::writeToProto(state.color,
+                                   [&]() { return layerInfo->mutable_requested_color(); });
     layerInfo->set_flags(state.flags);
 
     LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
@@ -2138,16 +2080,21 @@
     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);
     }
 
     auto buffer = mActiveBuffer;
     if (buffer != nullptr) {
-        LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer());
+        LayerProtoHelper::writeToProto(buffer,
+                                       [&]() { return layerInfo->mutable_active_buffer(); });
         LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
                                        layerInfo->mutable_buffer_transform());
     }
@@ -2171,9 +2118,11 @@
         (*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());
+    LayerProtoHelper::writeToProto(mSourceBounds,
+                                   [&]() { return layerInfo->mutable_source_bounds(); });
+    LayerProtoHelper::writeToProto(mScreenBounds,
+                                   [&]() { return layerInfo->mutable_screen_bounds(); });
+    LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
 }
 
 void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice) {
@@ -2187,10 +2136,10 @@
     const auto& compositionState = outputLayer->getState();
 
     const Rect& frame = compositionState.displayFrame;
-    LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
+    LayerProtoHelper::writeToProto(frame, [&]() { return layerInfo->mutable_hwc_frame(); });
 
     const FloatRect& crop = compositionState.sourceCrop;
-    LayerProtoHelper::writeToProto(crop, layerInfo->mutable_hwc_crop());
+    LayerProtoHelper::writeToProto(crop, [&]() { return layerInfo->mutable_hwc_crop(); });
 
     const int32_t transform =
             getCompositionLayer() ? static_cast<int32_t>(compositionState.bufferTransform) : 0;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 36885db..046482c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -45,7 +45,6 @@
 
 #include "Client.h"
 #include "FrameTracker.h"
-#include "LayerBE.h"
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
@@ -67,7 +66,6 @@
 class GraphicBuffer;
 class SurfaceFlinger;
 class LayerDebugInfo;
-class LayerBE;
 
 namespace compositionengine {
 class Layer;
@@ -97,9 +95,6 @@
     static std::atomic<int32_t> sSequence;
 
 public:
-    friend class LayerBE;
-    LayerBE& getBE() { return mBE; }
-    LayerBE& getBE() const { return mBE; }
     mutable bool contentDirty{false};
     // regions below are in window-manager space
     Region visibleRegion;
@@ -292,7 +287,7 @@
                                               uint64_t frameNumber);
     virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber);
     virtual bool setOverrideScalingMode(int32_t overrideScalingMode);
-    virtual bool setMetadata(LayerMetadata data);
+    virtual bool setMetadata(const LayerMetadata& data);
     virtual bool reparentChildren(const sp<IBinder>& layer);
     virtual void setChildrenDrawingParent(const sp<Layer>& layer);
     virtual bool reparent(const sp<IBinder>& newParentHandle);
@@ -437,9 +432,15 @@
 protected:
     virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                                     bool useIdentityTransform, Region& clearRegion,
-                                    renderengine::LayerSettings& layer) = 0;
+                                    const bool supportProtectedContent,
+                                    renderengine::LayerSettings& layer);
 
 public:
+    /*
+     * compositionengine::LayerFE overrides
+     */
+    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+
     virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
 
     virtual bool isHdrY410() const { return false; }
@@ -460,11 +461,6 @@
     bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
     void updateCursorPosition(const sp<const DisplayDevice>& display);
 
-    /*
-     * called after page-flip
-     */
-    virtual void onLayerDisplayed(const sp<Fence>& releaseFence);
-
     virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
     virtual void setTransformHint(uint32_t /*orientation*/) const { }
 
@@ -494,9 +490,10 @@
      * false otherwise.
      */
     bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, Region& clearRegion,
-                            renderengine::LayerSettings& layer);
+                            const bool supportProtectedContent, renderengine::LayerSettings& layer);
     bool prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
-                            Region& clearRegion, renderengine::LayerSettings& layer);
+                            Region& clearRegion, const bool supportProtectedContent,
+                            renderengine::LayerSettings& layer);
 
     /*
      * doTransaction - process the transaction. This is a good place to figure
@@ -570,11 +567,6 @@
 
     // -----------------------------------------------------------------------
 
-    bool createHwcLayer(HWComposer* hwc, const sp<DisplayDevice>& display);
-    bool destroyHwcLayer(const sp<DisplayDevice>& display);
-    bool destroyHwcLayersForAllDisplays();
-    bool destroyAllHwcLayersPlusChildren();
-
     bool hasHwcLayer(const sp<const DisplayDevice>& displayDevice);
     HWC2::Layer* getHwcLayer(const sp<const DisplayDevice>& displayDevice);
 
@@ -865,8 +857,6 @@
     wp<Layer> mCurrentParent;
     wp<Layer> mDrawingParent;
 
-    mutable LayerBE mBE;
-
     // Can only be accessed with the SF state lock held.
     bool mLayerDetached{false};
     // Can only be accessed with the SF state lock held.
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
deleted file mode 100644
index 9f63440..0000000
--- a/services/surfaceflinger/LayerBE.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 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
-#undef LOG_TAG
-#define LOG_TAG "LayerBE"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "Layer.h"
-
-namespace android {
-
-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) {
-    compositionInfo.layer = layer.compositionInfo.layer;
-    compositionInfo.layerName = layer.mLayer->getName().string();
-}
-
-void LayerBE::onLayerDisplayed(const sp<Fence>& releaseFence) {
-    mLayer->onLayerDisplayed(releaseFence);
-}
-
-}; // namespace android
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
deleted file mode 100644
index 51f7857..0000000
--- a/services/surfaceflinger/LayerBE.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <string.h>
-
-#include <ui/Fence.h>
-#include <utils/StrongPointer.h>
-
-#include "DisplayHardware/DisplayIdentification.h"
-
-namespace android {
-
-class LayerBE;
-
-struct CompositionInfo {
-    std::string layerName;
-    std::shared_ptr<LayerBE> layer;
-    struct {
-        DisplayId displayId;
-    } hwc;
-};
-
-class LayerBE {
-public:
-    friend class Layer;
-    friend class BufferLayer;
-    friend class BufferQueueLayer;
-    friend class BufferStateLayer;
-    friend class ColorLayer;
-    friend class SurfaceFlinger;
-
-    // For unit tests
-    friend class TestableSurfaceFlinger;
-
-    LayerBE(Layer* layer, std::string layerName);
-    explicit LayerBE(const LayerBE& layer);
-
-    void onLayerDisplayed(const sp<Fence>& releaseFence);
-
-    Layer*const mLayer;
-
-private:
-    CompositionInfo compositionInfo;
-};
-
-}; // namespace android
-
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 3289e8f..2d6d33c 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -18,53 +18,104 @@
 
 namespace android {
 namespace surfaceflinger {
-void LayerProtoHelper::writeToProto(const Region& region, RegionProto* regionProto) {
+
+void LayerProtoHelper::writePositionToProto(const float x, const float y,
+                                            std::function<PositionProto*()> getPositionProto) {
+    if (x != 0 || y != 0) {
+        // Use a lambda do avoid writing the object header when the object is empty
+        PositionProto* position = getPositionProto();
+        position->set_x(x);
+        position->set_y(y);
+    }
+}
+
+void LayerProtoHelper::writeSizeToProto(const uint32_t w, const uint32_t h,
+                                        std::function<SizeProto*()> getSizeProto) {
+    if (w != 0 || h != 0) {
+        // Use a lambda do avoid writing the object header when the object is empty
+        SizeProto* size = getSizeProto();
+        size->set_w(w);
+        size->set_h(h);
+    }
+}
+
+void LayerProtoHelper::writeToProto(const Region& region,
+                                    std::function<RegionProto*()> getRegionProto) {
+    if (region.isEmpty()) {
+        return;
+    }
+
     Region::const_iterator head = region.begin();
     Region::const_iterator const tail = region.end();
-    uint64_t address = reinterpret_cast<uint64_t>(&region);
-    regionProto->set_id(address);
+    // Use a lambda do avoid writing the object header when the object is empty
+    RegionProto* regionProto = getRegionProto();
     while (head != tail) {
-        RectProto* rectProto = regionProto->add_rect();
-        writeToProto(*head, rectProto);
+        std::function<RectProto*()> getProtoRect = [&]() { return regionProto->add_rect(); };
+        writeToProto(*head, getProtoRect);
         head++;
     }
 }
 
-void LayerProtoHelper::writeToProto(const Rect& rect, RectProto* rectProto) {
-    rectProto->set_left(rect.left);
-    rectProto->set_top(rect.top);
-    rectProto->set_bottom(rect.bottom);
-    rectProto->set_right(rect.right);
+void LayerProtoHelper::writeToProto(const Rect& rect, std::function<RectProto*()> getRectProto) {
+    if (rect.left != 0 || rect.right != 0 || rect.top != 0 || rect.bottom != 0) {
+        // Use a lambda do avoid writing the object header when the object is empty
+        RectProto* rectProto = getRectProto();
+        rectProto->set_left(rect.left);
+        rectProto->set_top(rect.top);
+        rectProto->set_bottom(rect.bottom);
+        rectProto->set_right(rect.right);
+    }
 }
 
-void LayerProtoHelper::writeToProto(const FloatRect& rect, FloatRectProto* rectProto) {
-    rectProto->set_left(rect.left);
-    rectProto->set_top(rect.top);
-    rectProto->set_bottom(rect.bottom);
-    rectProto->set_right(rect.right);
+void LayerProtoHelper::writeToProto(const FloatRect& rect,
+                                    std::function<FloatRectProto*()> getFloatRectProto) {
+    if (rect.left != 0 || rect.right != 0 || rect.top != 0 || rect.bottom != 0) {
+        // Use a lambda do avoid writing the object header when the object is empty
+        FloatRectProto* rectProto = getFloatRectProto();
+        rectProto->set_left(rect.left);
+        rectProto->set_top(rect.top);
+        rectProto->set_bottom(rect.bottom);
+        rectProto->set_right(rect.right);
+    }
 }
 
-void LayerProtoHelper::writeToProto(const half4 color, ColorProto* colorProto) {
-    colorProto->set_r(color.r);
-    colorProto->set_g(color.g);
-    colorProto->set_b(color.b);
-    colorProto->set_a(color.a);
+void LayerProtoHelper::writeToProto(const half4 color, std::function<ColorProto*()> getColorProto) {
+    if (color.r != 0 || color.g != 0 || color.b != 0 || color.a != 0) {
+        // Use a lambda do avoid writing the object header when the object is empty
+        ColorProto* colorProto = getColorProto();
+        colorProto->set_r(color.r);
+        colorProto->set_g(color.g);
+        colorProto->set_b(color.b);
+        colorProto->set_a(color.a);
+    }
 }
 
 void LayerProtoHelper::writeToProto(const ui::Transform& transform,
                                     TransformProto* transformProto) {
-    transformProto->set_dsdx(transform[0][0]);
-    transformProto->set_dtdx(transform[0][1]);
-    transformProto->set_dsdy(transform[1][0]);
-    transformProto->set_dtdy(transform[1][1]);
+    const uint32_t type = transform.getType();
+    transformProto->set_type(type);
+
+    if (type &
+        (ui::Transform::SCALE | ui::Transform::ROTATE | ui::Transform::TRANSLATE |
+         ui::Transform::UNKNOWN)) {
+        transformProto->set_dsdx(transform[0][0]);
+        transformProto->set_dtdx(transform[0][1]);
+        transformProto->set_dsdy(transform[1][0]);
+        transformProto->set_dtdy(transform[1][1]);
+    }
 }
 
 void LayerProtoHelper::writeToProto(const sp<GraphicBuffer>& buffer,
-                                    ActiveBufferProto* activeBufferProto) {
-    activeBufferProto->set_width(buffer->getWidth());
-    activeBufferProto->set_height(buffer->getHeight());
-    activeBufferProto->set_stride(buffer->getStride());
-    activeBufferProto->set_format(buffer->format);
+                                    std::function<ActiveBufferProto*()> getActiveBufferProto) {
+    if (buffer->getWidth() != 0 || buffer->getHeight() != 0 || buffer->getStride() != 0 ||
+        buffer->format != 0) {
+        // Use a lambda do avoid writing the object header when the object is empty
+        ActiveBufferProto* activeBufferProto = getActiveBufferProto();
+        activeBufferProto->set_width(buffer->getWidth());
+        activeBufferProto->set_height(buffer->getHeight());
+        activeBufferProto->set_stride(buffer->getStride());
+        activeBufferProto->set_format(buffer->format);
+    }
 }
 
 } // namespace surfaceflinger
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 6df5aea..dca9a5e 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -26,12 +26,18 @@
 namespace surfaceflinger {
 class LayerProtoHelper {
 public:
-    static void writeToProto(const Rect& rect, RectProto* rectProto);
-    static void writeToProto(const FloatRect& rect, FloatRectProto* rectProto);
-    static void writeToProto(const Region& region, RegionProto* regionProto);
-    static void writeToProto(const half4 color, ColorProto* colorProto);
+    static void writePositionToProto(const float x, const float y,
+                                     std::function<PositionProto*()> getPositionProto);
+    static void writeSizeToProto(const uint32_t w, const uint32_t h,
+                                 std::function<SizeProto*()> getSizeProto);
+    static void writeToProto(const Rect& rect, std::function<RectProto*()> getRectProto);
+    static void writeToProto(const FloatRect& rect,
+                             std::function<FloatRectProto*()> getFloatRectProto);
+    static void writeToProto(const Region& region, std::function<RegionProto*()> getRegionProto);
+    static void writeToProto(const half4 color, std::function<ColorProto*()> getColorProto);
     static void writeToProto(const ui::Transform& transform, TransformProto* transformProto);
-    static void writeToProto(const sp<GraphicBuffer>& buffer, ActiveBufferProto* activeBufferProto);
+    static void writeToProto(const sp<GraphicBuffer>& buffer,
+                             std::function<ActiveBufferProto*()> getActiveBufferProto);
 };
 
 } // namespace surfaceflinger
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
new file mode 100644
index 0000000..bd8548c
--- /dev/null
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -0,0 +1,255 @@
+/*
+ * 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> RegionSamplingThread::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);
+    }
+
+    const 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
+            const Rect bounds = Rect(layer->getBounds());
+            const 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.captureScreenCommon(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()) {
+        ALOGW("collected %zu median luma values for %zu descriptors", 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..ab06513
--- /dev/null
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -0,0 +1,84 @@
+/*
+ * 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();
+
+    // Add a listener to receive luma notifications. The luma reported via listener will
+    // report the median luma for the layers under the stopLayerHandle, in the samplingArea region.
+    void addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+                     const sp<IRegionSamplingListener>& listener);
+    // Remove the listener to stop receiving median luma notifications.
+    void removeListener(const sp<IRegionSamplingListener>& listener);
+    // Instruct the thread to perform a median luma sampling on the layers.
+    void sampleNow();
+
+private:
+    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());
+        }
+    };
+    std::vector<float> sampleBuffer(
+            const sp<GraphicBuffer>& buffer, const Point& leftTop,
+            const std::vector<RegionSamplingThread::Descriptor>& descriptors);
+
+    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/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 075e238..665179e 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -78,6 +78,11 @@
         mPeriod = period;
         mPhase = phase;
         mReferenceTime = referenceTime;
+        if (mTraceDetailedInfo) {
+            ATRACE_INT64("DispSync:Period", mPeriod);
+            ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
+            ATRACE_INT64("DispSync:Reference Time", mReferenceTime);
+        }
         ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64
               " mReferenceTime = %" PRId64,
               mName, ns2us(mPeriod), ns2us(mPhase), ns2us(mReferenceTime));
@@ -580,11 +585,6 @@
             ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase));
         }
 
-        if (mTraceDetailedInfo) {
-            ATRACE_INT64("DispSync:Period", mPeriod);
-            ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
-        }
-
         // Artificially inflate the period if requested.
         mPeriod += mPeriod * mRefreshSkipCount;
 
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 5d9cfde..78bf7c5 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -97,6 +97,13 @@
     return event;
 }
 
+DisplayEventReceiver::Event makeConfigChanged(uint32_t displayId, int32_t configId) {
+    DisplayEventReceiver::Event event;
+    event.header = {DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, displayId, systemTime()};
+    event.config.configId = configId;
+    return event;
+}
+
 } // namespace
 
 EventThreadConnection::EventThreadConnection(EventThread* eventThread,
@@ -203,6 +210,12 @@
     mVSyncSource->setPhaseOffset(phaseOffset);
 }
 
+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),
@@ -301,6 +314,13 @@
     mCondition.notify_all();
 }
 
+void EventThread::onConfigChanged(PhysicalDisplayId displayId, int32_t configId) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    mPendingEvents.push_back(makeConfigChanged(displayId, configId));
+    mCondition.notify_all();
+}
+
 void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
     DisplayEventConsumers consumers;
 
@@ -398,6 +418,7 @@
                                      const sp<EventThreadConnection>& connection) const {
     switch (event.header.type) {
         case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+        case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
             return true;
 
         case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index b275183..d5e3349 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -66,6 +66,9 @@
     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 {
@@ -109,6 +112,9 @@
 
     virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
 
+    // called when SF changes the active config and apps needs to be notified about the change
+    virtual void onConfigChanged(PhysicalDisplayId displayId, int32_t configId) = 0;
+
     virtual void dump(std::string& result) const = 0;
 
     virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
@@ -119,6 +125,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 {
@@ -148,10 +156,14 @@
 
     void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
 
+    void onConfigChanged(PhysicalDisplayId displayId, int32_t configId) override;
+
     void dump(std::string& result) const override;
 
     void setPhaseOffset(nsecs_t phaseOffset) override;
 
+    void pauseVsyncCallback(bool pause) override;
+
 private:
     friend EventThreadTest;
 
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/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 30fba3c..990318a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -153,6 +153,12 @@
     mConnections[handle->id]->thread->onScreenReleased();
 }
 
+void Scheduler::onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
+                                int32_t configId) {
+    RETURN_IF_INVALID();
+    mConnections[handle->id]->thread->onConfigChanged(displayId, configId);
+}
+
 void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, std::string& result) const {
     RETURN_IF_INVALID();
     mConnections.at(handle->id)->thread->dump(result);
@@ -163,6 +169,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();
@@ -293,6 +305,7 @@
 }
 
 void Scheduler::incrementFrameCounter() {
+    std::lock_guard<std::mutex> lock(mLayerHistoryLock);
     mLayerHistory.incrementCounter();
 }
 
@@ -317,25 +330,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());
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 7b5278c..7f113e7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -105,12 +105,19 @@
     // Should be called before the screen is turned off.
     void onScreenReleased(const sp<ConnectionHandle>& handle);
 
+    // Should be called when display config changed
+    void onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
+                         int32_t configId);
+
     // Should be called when dumpsys command is received.
     void dump(const sp<ConnectionHandle>& handle, std::string& result) const;
 
     // 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();
@@ -198,7 +205,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.
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index 0bf3ceb..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;
     }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e3f75e1..cd63a0e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -203,19 +203,6 @@
 const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
 const String16 sDump("android.permission.DUMP");
 
-constexpr float kSrgbRedX = 0.4123f;
-constexpr float kSrgbRedY = 0.2126f;
-constexpr float kSrgbRedZ = 0.0193f;
-constexpr float kSrgbGreenX = 0.3576f;
-constexpr float kSrgbGreenY = 0.7152f;
-constexpr float kSrgbGreenZ = 0.1192f;
-constexpr float kSrgbBlueX = 0.1805f;
-constexpr float kSrgbBlueY = 0.0722f;
-constexpr float kSrgbBlueZ = 0.9506f;
-constexpr float kSrgbWhiteX = 0.9505f;
-constexpr float kSrgbWhiteY = 1.0000f;
-constexpr float kSrgbWhiteZ = 1.0891f;
-
 constexpr float kDefaultRefreshRate = 60.f;
 constexpr float kPerformanceRefreshRate = 90.f;
 
@@ -288,6 +275,7 @@
         mDebugRegion(0),
         mDebugDisableHWC(0),
         mDebugDisableTransformHint(0),
+        mDebugEnableProtectedContent(false),
         mDebugInTransaction(0),
         mLastTransactionTime(0),
         mForceFullDamage(false),
@@ -297,7 +285,9 @@
         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) {
@@ -351,15 +341,7 @@
     }
     ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation);
 
-    auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
-    if (surfaceFlingerConfigsServiceV1_2) {
-        surfaceFlingerConfigsServiceV1_2->getDisplayNativePrimaries(
-                [&](auto tmpPrimaries) {
-                    memcpy(&mInternalDisplayPrimaries, &tmpPrimaries, sizeof(ui::DisplayPrimaries));
-                });
-    } else {
-        initDefaultDisplayNativePrimaries();
-    }
+    mInternalDisplayPrimaries = sysprop::getDisplayNativePrimaries();
 
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
@@ -396,6 +378,12 @@
     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);
 
@@ -576,9 +564,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, ConfigEvent::None);
+        } else {
+            mPhaseOffsets->setRefreshRateType(
+                    scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
+            setRefreshRateTo(RefreshRateType::DEFAULT, ConfigEvent::None);
+        }
     }));
 }
 
@@ -635,11 +638,6 @@
     mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
                                            mSfConnectionHandle.get());
 
-    if (mUse90Hz) {
-        mPhaseOffsets->setRefreshRateType(
-                scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
-    }
-
     // Get a RenderEngine for the given display / config (can't fail)
     int32_t renderEngineFeature = 0;
     renderEngineFeature |= (useColorManagement ?
@@ -648,9 +646,10 @@
                             renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0);
 
     // TODO(b/77156734): We need to stop casting and use HAL types when possible.
+    // Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display.
     mCompositionEngine->setRenderEngine(
             renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
-                                               renderEngineFeature));
+                                               renderEngineFeature, maxFrameBufferAcquiredBuffers));
 
     LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
             "Starting with vr flinger active is not currently supported.");
@@ -705,15 +704,16 @@
         ALOGE("Run StartPropertySetThread failed!");
     }
 
-    mScheduler->setExpiredIdleTimerCallback([this] {
-        Mutex::Autolock lock(mStateLock);
-        setRefreshRateTo(RefreshRateType::DEFAULT);
-    });
-    mScheduler->setResetIdleTimerCallback([this] {
-        Mutex::Autolock lock(mStateLock);
-        setRefreshRateTo(RefreshRateType::PERFORMANCE);
-    });
-
+    if (mUse90Hz) {
+        mScheduler->setExpiredIdleTimerCallback([this] {
+            Mutex::Autolock lock(mStateLock);
+            setRefreshRateTo(RefreshRateType::DEFAULT, ConfigEvent::None);
+        });
+        mScheduler->setResetIdleTimerCallback([this] {
+            Mutex::Autolock lock(mStateLock);
+            setRefreshRateTo(RefreshRateType::PERFORMANCE, ConfigEvent::None);
+        });
+    }
     mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
                                                                               *display->getId()),
                                                                       mTimeStats);
@@ -919,7 +919,8 @@
     return display->getActiveConfig();
 }
 
-void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode) {
+void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
+                                            ConfigEvent event) {
     ATRACE_CALL();
 
     Vector<DisplayInfo> configs;
@@ -949,36 +950,27 @@
 
     // 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};
+    std::lock_guard<std::mutex> lock(mActiveConfigLock);
+    mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken, event};
+
+    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();
     }
-    // This will trigger HWC refresh without resetting the idle timer.
-    repaintEverythingForHWC();
+    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::setActiveConfigInHWC() {
-    ATRACE_CALL();
+    std::vector<int32_t> allowedConfig;
+    allowedConfig.push_back(mode);
 
-    const auto display = getDisplayDevice(mUpcomingActiveConfig.displayToken);
-    if (!display) {
-        return;
-    }
-
-    const auto displayId = display->getId();
-    LOG_ALWAYS_FATAL_IF(!displayId);
-
-    ATRACE_INT("ActiveConfigModeHWC", mUpcomingActiveConfig.configId);
-    getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId);
-    mSetActiveConfigState = SetActiveConfigState::NOTIFIED_HWC;
-    ATRACE_INT("SetActiveConfigState", mSetActiveConfigState);
+    return setAllowedDisplayConfigs(displayToken, allowedConfig);
 }
 
 void SurfaceFlinger::setActiveConfigInternal() {
@@ -990,51 +982,80 @@
     const auto display = getDisplayDeviceLocked(mUpcomingActiveConfig.displayToken);
     display->setActiveConfig(mUpcomingActiveConfig.configId);
 
-    mSetActiveConfigState = SetActiveConfigState::NONE;
-    ATRACE_INT("SetActiveConfigState", mSetActiveConfigState);
-
     mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
     ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
+    if (mUpcomingActiveConfig.event != ConfigEvent::None) {
+        mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
+                                    mUpcomingActiveConfig.configId);
+    }
 }
 
-bool SurfaceFlinger::updateSetActiveConfigStateMachine() NO_THREAD_SAFETY_ANALYSIS {
+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) {
-        if (mSetActiveConfigState == SetActiveConfigState::NONE &&
-            display->getActiveConfig() != desiredActiveConfig.configId) {
-            // Step 1) Desired active config was set, it is different than the
-            // config currently in use. Notify HWC.
-            mUpcomingActiveConfig = desiredActiveConfig;
-            setActiveConfigInHWC();
-        } else if (mSetActiveConfigState == SetActiveConfigState::NOTIFIED_HWC) {
-            // Step 2) HWC was notified and we received refresh from it.
-            mSetActiveConfigState = SetActiveConfigState::REFRESH_RECEIVED;
-            ATRACE_INT("SetActiveConfigState", mSetActiveConfigState);
-            repaintEverythingForHWC();
-            // We do not want to give another frame to HWC while we are transitioning.
-            return false;
-        } else if (mSetActiveConfigState == SetActiveConfigState::REFRESH_RECEIVED &&
-                   !(mPreviousPresentFence != Fence::NO_FENCE &&
-                     (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled))) {
-            // Step 3) We received the present fence from the HWC, so we assume it
-            // successfully updated the config, hence we update SF.
-            setActiveConfigInternal();
-            // If the config changed again while we were transitioning, restart the
-            // process.
-            if (desiredActiveConfig != mUpcomingActiveConfig) {
-                mUpcomingActiveConfig = desiredActiveConfig;
-                setActiveConfigInHWC(); // sets the state to NOTIFY_HWC
-            }
-        }
+    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;
     }
-    return true;
+
+    // Desired active config was set, it is different than the config currently in use, however
+    // allowed configs might have change by the time we process the refresh.
+    // Make sure the desired config is still allowed
+    if (!isConfigAllowed(*display->getId(), desiredActiveConfig.configId)) {
+        std::lock_guard<std::mutex> lock(mActiveConfigLock);
+        mDesiredActiveConfig.configId = display->getActiveConfig();
+        return false;
+    }
+    mUpcomingActiveConfig = desiredActiveConfig;
+    const auto displayId = display->getId();
+    LOG_ALWAYS_FATAL_IF(!displayId);
+
+    ATRACE_INT("ActiveConfigModeHWC", mUpcomingActiveConfig.configId);
+    getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId);
+
+    // 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,
@@ -1285,17 +1306,23 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::addRegionSamplingListener(
-        const Rect& /*samplingArea*/, const sp<IBinder>& /*stopLayerHandle*/,
-        const sp<IRegionSamplingListener>& /*listener*/) {
+status_t SurfaceFlinger::addRegionSamplingListener(const Rect& samplingArea,
+                                                   const sp<IBinder>& stopLayerHandle,
+                                                   const sp<IRegionSamplingListener>& listener) {
+    if (!listener || samplingArea == Rect::INVALID_RECT) {
+        return BAD_VALUE;
+    }
+    mRegionSamplingThread->addListener(samplingArea, stopLayerHandle, listener);
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::removeRegionSamplingListener(
-        const sp<IRegionSamplingListener>& /*listener*/) {
+status_t SurfaceFlinger::removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) {
+    if (!listener) {
+        return BAD_VALUE;
+    }
+    mRegionSamplingThread->removeListener(listener);
     return NO_ERROR;
 }
-
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
@@ -1387,7 +1414,18 @@
     *compositorTiming = getBE().mCompositorTiming;
 }
 
-void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate) {
+bool SurfaceFlinger::isConfigAllowed(const DisplayId& displayId, int32_t config) {
+    std::lock_guard lock(mAllowedConfigsLock);
+
+    // if allowed configs are not set yet for this display, every config is considered allowed
+    if (mAllowedConfigs.find(displayId) == mAllowedConfigs.end()) {
+        return true;
+    }
+
+    return mAllowedConfigs[displayId]->isConfigAllowed(config);
+}
+
+void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, ConfigEvent event) {
     mPhaseOffsets->setRefreshRateType(refreshRate);
 
     const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
@@ -1422,6 +1460,11 @@
 
     auto configs = getHwComposer().getConfigs(*displayId);
     for (int i = 0; i < configs.size(); i++) {
+        if (!isConfigAllowed(*displayId, i)) {
+            ALOGV("Skipping config %d as it is not part of allowed configs", i);
+            continue;
+        }
+
         const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
         if (vsyncPeriod == 0) {
             continue;
@@ -1430,7 +1473,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) {
-            setDesiredActiveConfig(getInternalDisplayTokenLocked(), i);
+            setDesiredActiveConfig(getInternalDisplayTokenLocked(), i, event);
         }
     }
 }
@@ -1490,6 +1533,7 @@
 }
 
 void SurfaceFlinger::updateVrFlinger() {
+    ATRACE_CALL();
     if (!mVrFlinger)
         return;
     bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
@@ -1509,7 +1553,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.
@@ -1564,19 +1619,25 @@
     ATRACE_CALL();
     switch (what) {
         case MessageQueue::INVALIDATE: {
-            if (!updateSetActiveConfigStateMachine()) {
+            if (performSetActiveConfig()) {
                 break;
             }
 
-            // This call is made each time SF wakes up and creates a new frame.
-            mScheduler->incrementFrameCounter();
-
-            bool frameMissed = !mHadClientComposition && mPreviousPresentFence != Fence::NO_FENCE &&
+            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 = mPreviousPresentFence != Fence::NO_FENCE &&
                     (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled);
-            mFrameMissedCount += frameMissed;
-            ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+            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;
@@ -1611,6 +1672,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
@@ -1663,8 +1725,6 @@
 
     mVsyncModulator.onRefreshed(mHadClientComposition);
 
-    getBE().mEndOfFrameCompositionInfo = std::move(getBE().mCompositionInfo);
-
     mLayersWithQueuedFrames.clear();
 }
 
@@ -1705,10 +1765,8 @@
                 const auto& layer = currentLayers[i];
 
                 if (!layer->hasHwcLayer(displayDevice)) {
-                    if (!layer->createHwcLayer(&getHwComposer(), displayDevice)) {
-                        layer->forceClientComposition(displayDevice);
-                        continue;
-                    }
+                    layer->forceClientComposition(displayDevice);
+                    continue;
                 }
 
                 layer->setGeometry(displayDevice, i);
@@ -1779,12 +1837,9 @@
     for (const auto& [token, displayDevice] : mDisplays) {
         auto display = displayDevice->getCompositionDisplay();
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-            const auto displayId = display->getId();
             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);
         }
     }
 }
@@ -2132,6 +2187,10 @@
     mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
     mTransactionCompletedThread.sendCallbacks();
 
+    if (mLumaSampling) {
+        mRegionSamplingThread->sampleNow();
+    }
+
     ASSERT_ON_STACK_GUARD();
 }
 #pragma clang optimize on // b/119477596
@@ -2155,17 +2214,6 @@
     ATRACE_CALL();
     ALOGV("rebuildLayerStacks");
 
-    // We need to clear these out now as these may be holding on to a
-    // HWC2::Layer reference at the same time as the LayerBE::HWCInfo structure
-    // also holds a reference. When the set of visible layers is recomputed,
-    // some layers may be destroyed if the only thing keeping them alive was
-    // that list of visible layers associated with each display. The layer
-    // destruction code asserts that the HWC2::Layer is properly destroyed, but
-    // that doesn't happen if SurfaceFlingerBE::mCompositionInfo keeps it alive.
-    for (const auto& [token, display] : mDisplays) {
-        getBE().mCompositionInfo[token].clear();
-    }
-
     // rebuild the visible layer list per screen
     if (CC_UNLIKELY(mVisibleRegionsDirty)) {
         ATRACE_NAME("rebuildLayerStacks VR Dirty");
@@ -2192,42 +2240,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(displayDevice);
+                            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(displayDevice);
                     }
 
-                    // 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);
                         }
                     }
@@ -2439,16 +2487,19 @@
             getHwComposer().presentAndGetReleaseFences(*displayId);
         }
         display->getRenderSurface()->onPresentDisplayCompleted();
-        for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+        for (auto& layer : display->getOutputLayersOrderedByZ()) {
             sp<Fence> releaseFence = Fence::NO_FENCE;
+            bool usedClientComposition = true;
 
             // 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(displayDevice)) {
+            if (layer->getState().hwc) {
+                const auto& hwcState = *layer->getState().hwc;
                 releaseFence =
-                        getHwComposer().getLayerReleaseFence(*displayId,
-                                                             layer->getHwcLayer(displayDevice));
+                        getHwComposer().getLayerReleaseFence(*displayId, hwcState.hwcLayer.get());
+                usedClientComposition =
+                        hwcState.hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
             }
 
             // If the layer was client composited in the previous frame, we
@@ -2456,14 +2507,13 @@
             // 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(displayDevice) ==
-                Hwc2::IComposerClient::Composition::CLIENT) {
+            if (usedClientComposition) {
                 releaseFence =
                         Fence::merge("LayerRelease", releaseFence,
                                      display->getRenderSurface()->getClientTargetAcquireFence());
             }
 
-            layer->getBE().onLayerDisplayed(releaseFence);
+            layer->getLayerFE().onLayerDisplayed(releaseFence);
         }
 
         // We've got a list of layers needing fences, that are disjoint with
@@ -2473,7 +2523,7 @@
             sp<Fence> presentFence =
                     displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
             for (auto& layer : displayDevice->getLayersNeedingFences()) {
-                layer->getBE().onLayerDisplayed(presentFence);
+                layer->getCompositionLayer()->getLayerFE()->onLayerDisplayed(presentFence);
             }
         }
 
@@ -2918,6 +2968,10 @@
     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();
@@ -2933,7 +2987,10 @@
             inputHandles.add(layer->fillInputInfo());
         }
     });
-    mInputFlinger->setInputWindows(inputHandles);
+
+    mInputFlinger->setInputWindows(inputHandles,
+                                   mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener
+                                                                         : nullptr);
 }
 
 void SurfaceFlinger::commitInputWindowCommands() {
@@ -2983,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);
             }
         }
@@ -3161,21 +3214,6 @@
     }
 }
 
-void SurfaceFlinger::initDefaultDisplayNativePrimaries() {
-    mInternalDisplayPrimaries.red.X = kSrgbRedX;
-    mInternalDisplayPrimaries.red.Y = kSrgbRedY;
-    mInternalDisplayPrimaries.red.Z = kSrgbRedZ;
-    mInternalDisplayPrimaries.green.X = kSrgbGreenX;
-    mInternalDisplayPrimaries.green.Y = kSrgbGreenY;
-    mInternalDisplayPrimaries.green.Z = kSrgbGreenZ;
-    mInternalDisplayPrimaries.blue.X = kSrgbBlueX;
-    mInternalDisplayPrimaries.blue.Y = kSrgbBlueY;
-    mInternalDisplayPrimaries.blue.Z = kSrgbBlueZ;
-    mInternalDisplayPrimaries.white.X = kSrgbWhiteX;
-    mInternalDisplayPrimaries.white.Y = kSrgbWhiteY;
-    mInternalDisplayPrimaries.white.Z = kSrgbWhiteZ;
-}
-
 bool SurfaceFlinger::handlePageFlip()
 {
     ALOGV("handlePageFlip");
@@ -3278,6 +3316,9 @@
     auto display = displayDevice->getCompositionDisplay();
     const auto& displayState = display->getState();
     const auto displayId = display->getId();
+    auto& renderEngine = getRenderEngine();
+    const bool supportProtectedContent =
+            mDebugEnableProtectedContent && renderEngine.supportsProtectedContent();
 
     const Region bounds(displayState.bounds);
     const DisplayRenderArea renderArea(displayDevice);
@@ -3290,11 +3331,27 @@
     renderengine::DisplaySettings clientCompositionDisplay;
     std::vector<renderengine::LayerSettings> clientCompositionLayers;
     sp<GraphicBuffer> buf;
+    base::unique_fd fd;
 
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
-        buf = display->getRenderSurface()->dequeueBuffer();
+        if (displayDevice->isPrimary() && supportProtectedContent) {
+            bool needsProtected = false;
+            for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+                // If the layer is a protected layer, mark protected context is needed.
+                if (layer->isProtected()) {
+                    needsProtected = true;
+                    break;
+                }
+            }
+            if (needsProtected != renderEngine.isProtected() &&
+                renderEngine.useProtectedContext(needsProtected)) {
+                display->getRenderSurface()->setProtected(needsProtected);
+            }
+        }
+
+        buf = display->getRenderSurface()->dequeueBuffer(&fd);
 
         if (buf == nullptr) {
             ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
@@ -3316,7 +3373,6 @@
         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();
@@ -3368,8 +3424,9 @@
                         // guaranteed the FB is already cleared
                         renderengine::LayerSettings layerSettings;
                         Region dummyRegion;
-                        bool prepared = layer->prepareClientLayer(renderArea, clip, dummyRegion,
-                                                                  layerSettings);
+                        bool prepared =
+                                layer->prepareClientLayer(renderArea, clip, dummyRegion,
+                                                          supportProtectedContent, layerSettings);
 
                         if (prepared) {
                             layerSettings.source.buffer.buffer = nullptr;
@@ -3384,7 +3441,8 @@
                 case Hwc2::IComposerClient::Composition::CLIENT: {
                     renderengine::LayerSettings layerSettings;
                     bool prepared =
-                            layer->prepareClientLayer(renderArea, clip, clearRegion, layerSettings);
+                            layer->prepareClientLayer(renderArea, clip, clearRegion,
+                                                      supportProtectedContent, layerSettings);
                     if (prepared) {
                         clientCompositionLayers.push_back(layerSettings);
                     }
@@ -3415,8 +3473,8 @@
                 clientCompositionLayers.push_back(layerSettings);
             }
         }
-        getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers,
-                                     buf->getNativeBuffer(), readyFence);
+        renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
+                                buf->getNativeBuffer(), std::move(fd), readyFence);
     }
     return true;
 }
@@ -3648,13 +3706,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;
             }
         }
@@ -3972,6 +4033,10 @@
         flags |= eTraversalNeeded;
     }
 
+    if (inputWindowCommands.syncInputWindows) {
+        flags |= eTraversalNeeded;
+    }
+
     mPendingInputWindowCommands.merge(inputWindowCommands);
     return flags;
 }
@@ -4043,7 +4108,7 @@
         }
     }
 
-    layer->setMetadata(std::move(metadata));
+    layer->setMetadata(metadata);
 
     bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess();
     result = addClientLayer(client, *handle, *gbp, layer, *parent,
@@ -4440,7 +4505,9 @@
                   "    present offset: %9" PRId64 " ns\t     VSYNC period: %9" PRId64 " ns\n\n",
                   dispSyncPresentTimeOffset, getVsyncPeriod());
 
-    StringAppendF(&result, "Scheduler enabled. 90Hz feature: %s\n\n", mUse90Hz ? "on" : "off");
+    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);
 }
 
@@ -4847,6 +4914,8 @@
         case GET_ANIMATION_FRAME_STATS:
         case GET_HDR_CAPABILITIES:
         case SET_ACTIVE_CONFIG:
+        case SET_ALLOWED_DISPLAY_CONFIGS:
+        case GET_ALLOWED_DISPLAY_CONFIGS:
         case SET_ACTIVE_COLOR_MODE:
         case INJECT_VSYNC:
         case SET_POWER_MODE:
@@ -4926,9 +4995,9 @@
         code == IBinder::SYSPROPS_TRANSACTION) {
         return OK;
     }
-    // Numbers from 1000 to 1031 are currently use for backdoors. The code
+    // Numbers from 1000 to 1032 are currently use for backdoors. The code
     // in onTransact verifies that the user is root, and has access to use SF.
-    if (code >= 1000 && code <= 1031) {
+    if (code >= 1000 && code <= 1032) {
         ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
         return OK;
     }
@@ -5206,6 +5275,11 @@
                 }
                 return NO_ERROR;
             }
+            case 1032: {
+                n = data.readInt32();
+                mDebugEnableProtectedContent = n;
+                return NO_ERROR;
+            }
         }
     }
     return err;
@@ -5239,7 +5313,8 @@
                                        const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                        uint32_t reqWidth, uint32_t reqHeight,
                                        bool useIdentityTransform,
-                                       ISurfaceComposer::Rotation rotation) {
+                                       ISurfaceComposer::Rotation rotation,
+                                       bool captureSecureLayers) {
     ATRACE_CALL();
 
     if (!displayToken) return BAD_VALUE;
@@ -5262,7 +5337,7 @@
     }
 
     DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace,
-                                 renderAreaRotation);
+                                 renderAreaRotation, captureSecureLayers);
 
     auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display,
                                     std::placeholders::_1);
@@ -5424,6 +5499,13 @@
                                              static_cast<android_pixel_format>(reqPixelFormat), 1,
                                              usage, "screenshot");
 
+    return captureScreenCommon(renderArea, traverseLayers, *outBuffer, useIdentityTransform);
+}
+
+status_t SurfaceFlinger::captureScreenCommon(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;
@@ -5451,7 +5533,7 @@
         {
             Mutex::Autolock _l(mStateLock);
             renderArea.render([&] {
-                result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
+                result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
                                                  useIdentityTransform, forSystem, &fd);
             });
         }
@@ -5579,16 +5661,20 @@
     traverseLayers([&](Layer* layer) {
         renderengine::LayerSettings layerSettings;
         bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion,
-                                                  layerSettings);
+                                                  false, 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().useProtectedContext(false);
     getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer,
-                                 &drawFence);
+                                 std::move(bufferFence), &drawFence);
 
     *outSyncFd = drawFence.release();
 }
@@ -5618,6 +5704,13 @@
     return NO_ERROR;
 }
 
+void SurfaceFlinger::setInputWindowsFinished() {
+    Mutex::Autolock _l(mStateLock);
+
+    mPendingSyncInputWindows = false;
+    mTransactionCV.broadcast();
+}
+
 // ---------------------------------------------------------------------------
 
 void SurfaceFlinger::State::traverseInZOrder(const LayerVector::Visitor& visitor) const {
@@ -5649,6 +5742,112 @@
     }
 }
 
+void SurfaceFlinger::setAllowedDisplayConfigsInternal(
+        const android::sp<android::IBinder>& displayToken,
+        std::unique_ptr<const AllowedDisplayConfigs>&& allowedConfigs) {
+    const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+    if (!displayId) {
+        ALOGE("setAllowedDisplayConfigsInternal: getPhysicalDisplayId failed");
+        return;
+    }
+
+    ALOGV("Updating allowed configs");
+    {
+        std::lock_guard lock(mAllowedConfigsLock);
+        mAllowedConfigs[*displayId] = std::move(allowedConfigs);
+    }
+
+    // make sure that the current config is still allowed
+    int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId);
+    if (!isConfigAllowed(*displayId, currentConfigIndex)) {
+        // TODO(b/122906558): stop querying HWC for the available configs and instead use the cached
+        // configs queried on boot
+        auto configs = getHwComposer().getConfigs(*displayId);
+
+        for (int i = 0; i < configs.size(); i++) {
+            if (isConfigAllowed(*displayId, i)) {
+                // TODO: we switch to the first allowed config. In the future
+                // we may want to enhance this logic to pick a similar config
+                // to the current one
+                ALOGV("Old config is not allowed - switching to config %d", i);
+                setDesiredActiveConfig(displayToken, i, ConfigEvent::Changed);
+                break;
+            }
+        }
+    }
+}
+
+status_t SurfaceFlinger::setAllowedDisplayConfigs(const android::sp<android::IBinder>& displayToken,
+                                                  const std::vector<int32_t>& allowedConfigs) {
+    ATRACE_CALL();
+
+    if (!displayToken) {
+        ALOGE("setAllowedDisplayConfigs: displayToken is null");
+        return BAD_VALUE;
+    }
+
+    if (!allowedConfigs.size()) {
+        ALOGE("setAllowedDisplayConfigs: empty config set provided");
+        return BAD_VALUE;
+    }
+
+    {
+        ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+        const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+        if (!displayId) {
+            ALOGE("setAllowedDisplayConfigs: display not found");
+            return NAME_NOT_FOUND;
+        }
+    }
+
+    auto allowedDisplayConfigsBuilder = AllowedDisplayConfigs::Builder();
+    for (int config : allowedConfigs) {
+        ALOGV("setAllowedDisplayConfigs: Adding config to the allowed configs = %d", config);
+        allowedDisplayConfigsBuilder.addConfig(config);
+    }
+    auto allowedDisplayConfigs = allowedDisplayConfigsBuilder.build();
+    postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS {
+        setAllowedDisplayConfigsInternal(displayToken, std::move(allowedDisplayConfigs));
+    }));
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::getAllowedDisplayConfigs(const android::sp<android::IBinder>& displayToken,
+                                                  std::vector<int32_t>* outAllowedConfigs) {
+    ATRACE_CALL();
+
+    if (!displayToken) {
+        ALOGE("getAllowedDisplayConfigs: displayToken is null");
+        return BAD_VALUE;
+    }
+
+    if (!outAllowedConfigs) {
+        ALOGE("getAllowedDisplayConfigs: outAllowedConfigs is null");
+        return BAD_VALUE;
+    }
+
+    ConditionalLock stateLock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+    const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+    if (!displayId) {
+        ALOGE("getAllowedDisplayConfigs: display not found");
+        return NAME_NOT_FOUND;
+    }
+
+    std::lock_guard allowedConfigLock(mAllowedConfigsLock);
+    auto allowedConfigIterator = mAllowedConfigs.find(displayId.value());
+    if (allowedConfigIterator != mAllowedConfigs.end()) {
+        allowedConfigIterator->second->getAllowedConfigs(outAllowedConfigs);
+    }
+
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+void SetInputWindowsListener::onSetInputWindowsFinished() {
+    mFlinger->setInputWindowsFinished();
+}
+
 }; // namespace android
 
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 36302d5..8f80175 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>
@@ -46,6 +47,7 @@
 #include <utils/Trace.h>
 #include <utils/threads.h>
 
+#include "AllowedDisplayConfigs.h"
 #include "Barrier.h"
 #include "BufferStateLayerCache.h"
 #include "DisplayDevice.h"
@@ -53,9 +55,9 @@
 #include "DisplayHardware/HWComposer.h"
 #include "Effects/Daltonizer.h"
 #include "FrameTracker.h"
-#include "LayerBE.h"
 #include "LayerStats.h"
 #include "LayerVector.h"
+#include "RegionSamplingThread.h"
 #include "Scheduler/DispSync.h"
 #include "Scheduler/EventThread.h"
 #include "Scheduler/MessageQueue.h"
@@ -103,7 +105,6 @@
 class SurfaceFlingerBE;
 class TimeStats;
 class VSyncSource;
-struct CompositionInfo;
 
 namespace compositionengine {
 class DisplaySurface;
@@ -196,11 +197,16 @@
     // use to differentiate callbacks from different hardware composer
     // instances. Each hardware composer instance gets a different sequence id.
     int32_t mComposerSequenceId;
-
-    std::map<wp<IBinder>, std::vector<CompositionInfo>> mCompositionInfo;
-    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,
@@ -348,6 +354,8 @@
         return mTransactionCompletedThread;
     }
 
+    void setInputWindowsFinished();
+
 private:
     friend class Client;
     friend class DisplayEventConnection;
@@ -357,6 +365,7 @@
     friend class BufferQueueLayer;
     friend class BufferStateLayer;
     friend class MonitoredProducer;
+    friend class RegionSamplingThread;
 
     // For unit tests
     friend class TestableSurfaceFlinger;
@@ -429,7 +438,8 @@
     status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
                            const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
                            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-                           bool useIdentityTransform, ISurfaceComposer::Rotation rotation) override;
+                           bool useIdentityTransform, ISurfaceComposer::Rotation rotation,
+                           bool captureSecureLayers) override;
     status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
                            const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
                            const Rect& sourceCrop, float frameScale, bool childrenOnly) override;
@@ -477,6 +487,11 @@
     status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
                                        const sp<IRegionSamplingListener>& listener) override;
     status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
+    status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                      const std::vector<int32_t>& allowedConfigs) override;
+    status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                      std::vector<int32_t>* outAllowedConfigs) override;
+
     /* ------------------------------------------------------------------------
      * DeathRecipient interface
      */
@@ -506,23 +521,29 @@
     void signalLayerUpdate();
     void signalRefresh();
 
+    enum class ConfigEvent { None, Changed };
+
     // called on the main thread in response to initializeDisplays()
     void onInitializeDisplays() REQUIRES(mStateLock);
     // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
-    void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock);
-    // Calls setActiveConfig in HWC.
-    void setActiveConfigInHWC();
+    void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode, ConfigEvent event)
+            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 pannel on the next refresh, and when
+    // 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
-    // the invalidate process should continue.
-    bool updateSetActiveConfigStateMachine();
+    // 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);
 
+    // called on the main thread in response to setAllowedDisplayConfigs()
+    void setAllowedDisplayConfigsInternal(
+            const sp<IBinder>& displayToken,
+            std::unique_ptr<const AllowedDisplayConfigs>&& allowedConfigs) REQUIRES(mStateLock);
+
     // Returns whether the transaction actually modified any state
     bool handleMessageTransaction();
 
@@ -624,6 +645,8 @@
     status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
                                  sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
                                  bool useIdentityTransform);
+    status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+                                 const sp<GraphicBuffer>& buffer, bool useIdentityTransform);
     status_t captureScreenImplLocked(const RenderArea& renderArea,
                                      TraverseLayersFunction traverseLayers,
                                      ANativeWindowBuffer* buffer, bool useIdentityTransform,
@@ -686,10 +709,6 @@
     // region of all screens presenting this layer stack.
     void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
 
-    // Initialize structures containing information about the internal
-    // display's native color coordinates using default data
-    void initDefaultDisplayNativePrimaries();
-
     /* ------------------------------------------------------------------------
      * H/W composer
      */
@@ -789,7 +808,10 @@
 
     // Sets the refresh rate by switching active configs, if they are available for
     // the desired refresh rate.
-    void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType) REQUIRES(mStateLock);
+    void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType, ConfigEvent event)
+            REQUIRES(mStateLock);
+
+    bool isConfigAllowed(const DisplayId& displayId, int32_t config);
 
     /*
      * Display identification
@@ -974,6 +996,7 @@
     int mDebugRegion;
     int mDebugDisableHWC;
     int mDebugDisableTransformHint;
+    bool mDebugEnableProtectedContent;
     volatile nsecs_t mDebugInSwapBuffers;
     volatile nsecs_t mDebugInTransaction;
     nsecs_t mLastTransactionTime;
@@ -989,6 +1012,9 @@
 
     TransactionCompletedThread mTransactionCompletedThread;
 
+    bool mLumaSampling = true;
+    sp<RegionSamplingThread> mRegionSamplingThread = new RegionSamplingThread(*this);
+
     // Restrict layers to use two buffers in their bufferqueues.
     bool mLayerTripleBufferingDisabled = false;
 
@@ -1076,23 +1102,20 @@
      * Scheduler
      */
     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;
 
-    // The following structs are used for configuring active config state at a desired time,
-    // which is once per vsync at invalidate time.
-    enum SetActiveConfigState {
-        NONE,            // not in progress
-        NOTIFIED_HWC,    // call to HWC has been made
-        REFRESH_RECEIVED // onRefresh was received from HWC
-    };
-    std::atomic<SetActiveConfigState> mSetActiveConfigState = SetActiveConfigState::NONE;
+    std::mutex mAllowedConfigsLock;
+    std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs
+            GUARDED_BY(mAllowedConfigsLock);
 
     struct ActiveConfigInfo {
         int configId;
         sp<IBinder> displayToken;
+        ConfigEvent event;
 
         bool operator!=(const ActiveConfigInfo& other) const {
             if (configId != other.configId) {
@@ -1109,6 +1132,11 @@
     // 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;
 
@@ -1117,6 +1145,9 @@
     InputWindowCommands mInputWindowCommands;
 
     ui::DisplayPrimaries mInternalDisplayPrimaries;
+
+    sp<SetInputWindowsListener> mSetInputWindowsListener;
+    bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
 };
 }; // namespace android
 
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index b654ba7..e676d20 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -7,6 +7,7 @@
 #include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
 
+#include <cstdlib>
 #include <tuple>
 
 #include "SurfaceFlingerProperties.h"
@@ -15,6 +16,7 @@
 namespace sysprop {
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
+using ::android::hardware::configstore::V1_2::DisplayPrimaries;
 using ::android::hardware::graphics::common::V1_2::Dataspace;
 using ::android::hardware::graphics::common::V1_2::PixelFormat;
 
@@ -242,5 +244,47 @@
     return static_cast<int32_t>(defaultValue);
 }
 
+#define DISPLAY_PRIMARY_SIZE 3
+
+constexpr float kSrgbRedX = 0.4123f;
+constexpr float kSrgbRedY = 0.2126f;
+constexpr float kSrgbRedZ = 0.0193f;
+constexpr float kSrgbGreenX = 0.3576f;
+constexpr float kSrgbGreenY = 0.7152f;
+constexpr float kSrgbGreenZ = 0.1192f;
+constexpr float kSrgbBlueX = 0.1805f;
+constexpr float kSrgbBlueY = 0.0722f;
+constexpr float kSrgbBlueZ = 0.9506f;
+constexpr float kSrgbWhiteX = 0.9505f;
+constexpr float kSrgbWhiteY = 1.0000f;
+constexpr float kSrgbWhiteZ = 1.0891f;
+
+DisplayPrimaries getDisplayNativePrimaries() {
+    auto mDisplay_primary_red = SurfaceFlingerProperties::display_primary_red();
+    auto mDisplay_primary_green = SurfaceFlingerProperties::display_primary_green();
+    auto mDisplay_primary_blue = SurfaceFlingerProperties::display_primary_blue();
+    auto mDisplay_primary_white = SurfaceFlingerProperties::display_primary_white();
+    // To avoid null point exception.
+    mDisplay_primary_red.resize(DISPLAY_PRIMARY_SIZE);
+    mDisplay_primary_green.resize(DISPLAY_PRIMARY_SIZE);
+    mDisplay_primary_blue.resize(DISPLAY_PRIMARY_SIZE);
+    mDisplay_primary_white.resize(DISPLAY_PRIMARY_SIZE);
+    DisplayPrimaries primaries =
+            {{static_cast<float>(mDisplay_primary_red[0].value_or(kSrgbRedX)),
+              static_cast<float>(mDisplay_primary_red[1].value_or(kSrgbRedY)),
+              static_cast<float>(mDisplay_primary_red[2].value_or(kSrgbRedZ))},
+             {static_cast<float>(mDisplay_primary_green[0].value_or(kSrgbGreenX)),
+              static_cast<float>(mDisplay_primary_green[1].value_or(kSrgbGreenY)),
+              static_cast<float>(mDisplay_primary_green[2].value_or(kSrgbGreenZ))},
+             {static_cast<float>(mDisplay_primary_blue[0].value_or(kSrgbBlueX)),
+              static_cast<float>(mDisplay_primary_blue[1].value_or(kSrgbBlueY)),
+              static_cast<float>(mDisplay_primary_blue[2].value_or(kSrgbBlueZ))},
+             {static_cast<float>(mDisplay_primary_white[0].value_or(kSrgbWhiteX)),
+              static_cast<float>(mDisplay_primary_white[1].value_or(kSrgbWhiteY)),
+              static_cast<float>(mDisplay_primary_white[2].value_or(kSrgbWhiteZ))}};
+
+    return primaries;
+}
+
 } // namespace sysprop
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 9b26883..c86880e 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -53,6 +53,8 @@
 
 int32_t wcg_composition_pixel_format(
         android::hardware::graphics::common::V1_2::PixelFormat defaultValue);
+
+android::hardware::configstore::V1_2::DisplayPrimaries getDisplayNativePrimaries();
 } // namespace sysprop
 } // namespace android
 #endif // SURFACEFLINGERPROPERTIES_H_
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index 5c72fea..7288232 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -132,7 +132,6 @@
 
 LayerProtoParser::Region LayerProtoParser::generateRegion(const RegionProto& regionProto) {
     LayerProtoParser::Region region;
-    region.id = regionProto.id();
     for (int i = 0; i < regionProto.rect_size(); i++) {
         const RectProto& rectProto = regionProto.rect(i);
         region.rects.push_back(generateRect(rectProto));
@@ -199,13 +198,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 72cbfac..fd4695e 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -1,156 +1,157 @@
 // 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;
 
-  optional TransformProto effective_transform = 43;
-  optional FloatRectProto source_bounds = 44;
-  optional FloatRectProto bounds = 45;
-  optional FloatRectProto screen_bounds = 46;
+  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;
+  int32 type = 5;
 }
 
 message RegionProto {
-  optional uint64 id = 1;
+  reserved 1;  // Previously: uint64 id
   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/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index cc7b280..429636b 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -250,3 +250,39 @@
     access: Readonly
     prop_name: "ro.surface_flinger.wcg_composition_pixel_format"
 }
+
+# Return the native panel primary data. The data includes red, green,
+# blue and white. The primary format is CIE 1931 XYZ color space.
+# If unspecified, the primaries is sRGB gamut by default.
+
+prop {
+    api_name: "display_primary_red"
+    type: DoubleList
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.surface_flinger.display_primary_red"
+}
+
+prop {
+    api_name: "display_primary_green"
+    type: DoubleList
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.surface_flinger.display_primary_green"
+}
+
+prop {
+    api_name: "display_primary_blue"
+    type: DoubleList
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.surface_flinger.display_primary_blue"
+}
+
+prop {
+    api_name: "display_primary_white"
+    type: DoubleList
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.surface_flinger.display_primary_white"
+}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 181dac6..34cdff7 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -33,6 +33,7 @@
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
+#include <private/android_filesystem_config.h>
 
 #include <ui/ColorSpace.h>
 #include <ui/DisplayInfo.h>
@@ -41,6 +42,8 @@
 
 #include <math.h>
 #include <math/vec3.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "BufferGenerator.h"
 
@@ -1201,6 +1204,56 @@
               composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
 }
 
+/** RAII Wrapper around get/seteuid */
+class UIDFaker {
+    uid_t oldId;
+public:
+    UIDFaker(uid_t uid) {
+        oldId = geteuid();
+        seteuid(uid);
+    }
+    ~UIDFaker() {
+        seteuid(oldId);
+    }
+};
+
+TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<GraphicBuffer> outBuffer;
+    Transaction()
+            .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
+            .apply(true);
+    ASSERT_EQ(PERMISSION_DENIED,
+              composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+    UIDFaker f(AID_SYSTEM);
+
+    // By default the system can capture screenshots with secure layers but they
+    // will be blacked out
+    ASSERT_EQ(NO_ERROR,
+              composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+    {
+        SCOPED_TRACE("as system");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
+    // to receive them...we are expected to take care with the results.
+    ASSERT_EQ(NO_ERROR,
+              composer->captureScreen(mDisplay, &outBuffer,
+                      ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
+                      Rect(), 0, 0, false,
+                      ISurfaceComposer::eRotateNone, true));
+    ScreenCapture sc(outBuffer);
+    sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
 TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
     const Rect top(0, 0, 32, 16);
     const Rect bottom(0, 16, 32, 32);
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 42bdccc..6deec29 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -312,7 +312,7 @@
                 .WillRepeatedly(
                         [](const renderengine::DisplaySettings& displaySettings,
                            const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
-                           ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+                           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);
@@ -351,7 +351,7 @@
                 .WillRepeatedly(
                         [](const renderengine::DisplaySettings& displaySettings,
                            const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
-                           ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+                           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);
@@ -580,7 +580,8 @@
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([](const renderengine::DisplaySettings& displaySettings,
                              const std::vector<renderengine::LayerSettings>& layerSettings,
-                             ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+                             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);
@@ -624,7 +625,8 @@
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([](const renderengine::DisplaySettings& displaySettings,
                              const std::vector<renderengine::LayerSettings>& layerSettings,
-                             ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+                             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);
@@ -693,7 +695,8 @@
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([](const renderengine::DisplaySettings& displaySettings,
                              const std::vector<renderengine::LayerSettings>& layerSettings,
-                             ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+                             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);
@@ -766,16 +769,16 @@
     }
 
     static void injectLayer(CompositionTest* test, sp<Layer> layer) {
-        std::vector<std::unique_ptr<compositionengine::OutputLayer>> outputLayers;
-        outputLayers.emplace_back(
-                test->mDisplay->getCompositionDisplay()
-                        ->getOrCreateOutputLayer(layer->getCompositionLayer(), layer));
-        test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(std::move(outputLayers));
-
         EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
                 .WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
 
-        layer->createHwcLayer(&test->mFlinger.getHwComposer(), test->mDisplay);
+        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);
 
@@ -791,10 +794,6 @@
 
         test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(
                 std::vector<std::unique_ptr<compositionengine::OutputLayer>>());
-
-        for (auto layer : test->mFlinger.mutableDrawingState().layersSortedByZ) {
-            layer->destroyHwcLayer(test->mDisplay);
-        }
         test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
     }
 };
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 19f308b..1487d47 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -1322,32 +1322,6 @@
     EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(nullptr, primaries));
 }
 
-TEST_F(GetDisplayNativePrimaries, internalDisplayWithDefaultPrimariesData) {
-    auto injector = SimplePrimaryDisplayCase::Display::makeFakeExistingDisplayInjector(this);
-    injector.inject();
-    auto internalDisplayToken = injector.token();
-    // A nullptr would trigger a different execution path than what's being tested here
-    EXPECT_NE(nullptr, internalDisplayToken.get());
-
-    mFlinger.initDefaultDisplayNativePrimaries();
-
-    ui::DisplayPrimaries primaries;
-    // Expecting sRGB primaries
-    EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries));
-    EXPECT_EQ(primaries.red.X, 0.4123f);
-    EXPECT_EQ(primaries.red.Y, 0.2126f);
-    EXPECT_EQ(primaries.red.Z, 0.0193f);
-    EXPECT_EQ(primaries.green.X, 0.3576f);
-    EXPECT_EQ(primaries.green.Y, 0.7152f);
-    EXPECT_EQ(primaries.green.Z, 0.1192f);
-    EXPECT_EQ(primaries.blue.X, 0.1805f);
-    EXPECT_EQ(primaries.blue.Y, 0.0722f);
-    EXPECT_EQ(primaries.blue.Z, 0.9506f);
-    EXPECT_EQ(primaries.white.X, 0.9505f);
-    EXPECT_EQ(primaries.white.Y, 1.0000f);
-    EXPECT_EQ(primaries.white.Z, 1.0891f);
-}
-
 TEST_F(GetDisplayNativePrimaries, internalDisplayWithPrimariesData) {
     auto injector = SimplePrimaryDisplayCase::Display::makeFakeExistingDisplayInjector(this);
     injector.inject();
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 3a7cfba..406ec81 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -44,6 +44,7 @@
     MOCK_METHOD1(setVSyncEnabled, void(bool));
     MOCK_METHOD1(setCallback, void(VSyncSource::Callback*));
     MOCK_METHOD1(setPhaseOffset, void(nsecs_t));
+    MOCK_METHOD1(pauseVsyncCallback, void(bool));
 };
 
 } // namespace
@@ -71,6 +72,7 @@
 
     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,
@@ -79,10 +81,13 @@
     void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
     void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
                                                 bool expectedConnected);
+    void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
+                                                      int32_t expectedConfigId);
 
     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;
@@ -108,6 +113,9 @@
     EXPECT_CALL(mVSyncSource, setPhaseOffset(_))
             .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
 
+    EXPECT_CALL(mVSyncSource, pauseVsyncCallback(_))
+            .WillRepeatedly(Invoke(mVSyncPauseVsyncCallbackCallRecorder.getInvocable()));
+
     createThread();
     mConnection = createConnection(mConnectionEventCallRecorder);
 
@@ -157,6 +165,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;
@@ -200,6 +214,16 @@
     EXPECT_EQ(expectedConnected, event.hotplug.connected);
 }
 
+void EventThreadTest::expectConfigChangedEventReceivedByConnection(
+        PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId) {
+    auto args = mConnectionEventCallRecorder.waitForCall();
+    ASSERT_TRUE(args.has_value());
+    const auto& event = std::get<0>(args.value());
+    EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, event.header.type);
+    EXPECT_EQ(expectedDisplayId, event.header.displayId);
+    EXPECT_EQ(expectedConfigId, event.config.configId);
+}
+
 namespace {
 
 /* ------------------------------------------------------------------------
@@ -406,6 +430,16 @@
     expectVSyncSetPhaseOffsetCallReceived(321);
 }
 
+TEST_F(EventThreadTest, pauseVsyncCallbackForwardsToVSyncSource) {
+    mThread->pauseVsyncCallback(true);
+    expectVSyncPauseVsyncCallbackCallReceived(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);
@@ -426,5 +460,15 @@
     expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, true);
 }
 
+TEST_F(EventThreadTest, postConfigChangedPrimary) {
+    mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 7);
+    expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7);
+}
+
+TEST_F(EventThreadTest, postConfigChangedExternal) {
+    mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, 5);
+    expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5);
+}
+
 } // namespace
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
index 5e82225..ea39bf5 100644
--- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
@@ -140,7 +140,7 @@
                                                         mExpiredTimerCallback.getInvocable());
     // The start hasn't happened, so the callback does not happen.
     EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
-    EXPECT_FALSE(mResetTimerCallback.waitForCall(1us).has_value());
+    EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
     mIdleTimer->stop();
     // Final quick check that no more callback were observed.
     EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
@@ -159,7 +159,7 @@
     EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
     // Once reset, it should generate another
     mIdleTimer->reset();
-    EXPECT_TRUE(mResetTimerCallback.waitForCall(1ms).has_value());
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
     EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
     mIdleTimer->stop();
     // Final quick check that no more callback were observed.
@@ -171,7 +171,7 @@
     mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
                                                         mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
-    EXPECT_TRUE(mResetTimerCallback.waitForCall(1us).has_value());
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
     EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
     mIdleTimer->stop();
 }
@@ -180,21 +180,21 @@
     mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
                                                         mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
-    EXPECT_TRUE(mResetTimerCallback.waitForCall(1ms).has_value());
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
     EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
 
     mIdleTimer->stop();
     clearPendingCallbacks();
     mIdleTimer->reset();
     EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
-    EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value());
+    EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
 }
 
 TEST_F(IdleTimerTest, noCallbacksAfterStopTest) {
     mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
                                                         mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
-    EXPECT_TRUE(mResetTimerCallback.waitForCall(1ms).has_value());
+    EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
 
     mIdleTimer->stop();
     clearPendingCallbacks();
@@ -202,7 +202,7 @@
 
     // No more idle events should be observed
     EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
-    EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value());
+    EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
index 92c9f92..75a061b 100644
--- a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
@@ -62,17 +62,6 @@
     metadata.mMap[2] = std::vector<uint8_t>{'a', 'b'};
     ASSERT_EQ(0, metadata.getInt32(2, 0));
 
-    LayerMetadata second;
-    std::vector<uint8_t> someData{'c', 'd', '\0'};
-    second.mMap[2] = someData;
-    second.setInt32(6, 5);
-    metadata.merge(second);
-
-    ASSERT_EQ(3, metadata.mMap.size());
-    ASSERT_EQ(someData, second.mMap[2]);
-    ASSERT_EQ(5, metadata.getInt32(6, 0));
-    ASSERT_EQ(2, metadata.getInt32(4, 0));
-
     Parcel p;
     metadata.writeToParcel(&p);
     LayerMetadata reconstructed;
@@ -82,5 +71,39 @@
     ASSERT_EQ(metadata.mMap, reconstructed.mMap);
 }
 
+TEST_F(LayerMetadataTest, merge) {
+    LayerMetadata metadata;
+    metadata.setInt32(4, 2);
+    metadata.mMap[2] = std::vector<uint8_t>{'a', 'b'};
+
+    LayerMetadata second;
+    std::vector<uint8_t> someData{'c', 'd', '\0'};
+    second.mMap[2] = someData;
+    second.setInt32(6, 5);
+    second.mMap[4].clear(); // will not delete if eraseEmpty is false
+    bool changed = metadata.merge(second);
+
+    ASSERT_TRUE(changed);
+    ASSERT_EQ(3, metadata.mMap.size());
+    ASSERT_EQ(someData, second.mMap[2]);
+    ASSERT_EQ(5, metadata.getInt32(6, 0));
+    ASSERT_TRUE(metadata.mMap.at(4).empty());
+
+    LayerMetadata withErase;
+    withErase.mMap[6].clear();
+    changed = metadata.merge(withErase, true /* eraseEmpty */);
+    ASSERT_TRUE(changed);
+    ASSERT_EQ(2, metadata.mMap.size());
+    ASSERT_EQ(someData, second.mMap[2]);
+    ASSERT_EQ(true, metadata.has(4));
+
+    // test for change detection
+    LayerMetadata third;
+    third.mMap[2] = someData;
+    third.mMap[5].clear();
+    changed = metadata.merge(third);
+    ASSERT_FALSE(changed);
+}
+
 } // namespace
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 6313f1f..d61973e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -289,10 +289,6 @@
         return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
     }
 
-    void initDefaultDisplayNativePrimaries() {
-        mFlinger->SurfaceFlinger::initDefaultDisplayNativePrimaries();
-    }
-
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 589237d..cb4a300 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -33,12 +33,14 @@
     MOCK_METHOD0(onScreenReleased, void());
     MOCK_METHOD0(onScreenAcquired, void());
     MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
+    MOCK_METHOD2(onConfigChanged, void(PhysicalDisplayId, int32_t));
     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 b49d894..a7fd912 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -392,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;
@@ -437,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();
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 32e19f7..73fc7b2 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -688,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;