Merge "getCallingSid: get calling security context"
diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc
index 5c28c9d..6c86c21 100644
--- a/cmds/atrace/atrace_userdebug.rc
+++ b/cmds/atrace/atrace_userdebug.rc
@@ -5,6 +5,12 @@
 # Access control to these files is now entirely in selinux policy.
 
 on post-fs
+    # On userdebug allow to enable any event via the generic
+    # set_event interface:
+    # echo sched/foo > set_event == echo 1 > events/sched/foo/enable.
+    chmod 0666 /sys/kernel/tracing/set_event
+    chmod 0666 /sys/kernel/debug/tracing/set_event
+
     chmod 0666 /sys/kernel/tracing/events/workqueue/enable
     chmod 0666 /sys/kernel/debug/tracing/events/workqueue/enable
     chmod 0666 /sys/kernel/tracing/events/regulator/enable
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 849eb44..6596fa2 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -98,9 +98,10 @@
     return binder::Status::ok();
 }
 
-binder::Status DumpstateService::startBugreport(int, int bugreport_mode, int32_t* returned_id) {
-    // TODO(111441001): return a request id here.
-    *returned_id = -1;
+binder::Status DumpstateService::startBugreport(const android::base::unique_fd& bugreport_fd,
+                                                const android::base::unique_fd& screenshot_fd,
+                                                int bugreport_mode,
+                                                const sp<IDumpstateListener>& listener) {
     MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
 
     if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL &&
@@ -114,9 +115,20 @@
                          StringPrintf("Invalid bugreport mode: %d", bugreport_mode));
     }
 
+    if (bugreport_fd.get() == -1 || screenshot_fd.get() == -1) {
+        return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Invalid file descriptor");
+    }
+
     std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
-    options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode));
+    options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd,
+                        screenshot_fd);
+
+    std::lock_guard<std::mutex> lock(lock_);
+    // TODO(b/111441001): Disallow multiple simultaneous bugreports.
     ds_.SetOptions(std::move(options));
+    if (listener != nullptr) {
+        ds_.listener_ = listener;
+    }
 
     pthread_t thread;
     status_t err = pthread_create(&thread, nullptr, callAndNotify, &ds_);
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 58095b3..1705317 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -20,6 +20,7 @@
 #include <mutex>
 #include <vector>
 
+#include <android-base/unique_fd.h>
 #include <binder/BinderService.h>
 
 #include "android/os/BnDumpstate.h"
@@ -41,7 +42,9 @@
                                bool getSectionDetails,
                                sp<IDumpstateToken>* returned_token) override;
 
-    binder::Status startBugreport(int fd, int bugreport_mode, int32_t* returned_id) override;
+    binder::Status startBugreport(const android::base::unique_fd& bugreport_fd,
+                                  const android::base::unique_fd& screenshot_fd, int bugreport_mode,
+                                  const sp<IDumpstateListener>& listener) override;
 
   private:
     Dumpstate& ds_;
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 617eab3..d24c953 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -25,8 +25,6 @@
   * {@hide}
   */
 interface IDumpstate {
-
-
     // TODO: remove method once startBugReport is used by Shell.
     /*
      * Sets the listener for this dumpstate progress.
@@ -63,6 +61,12 @@
 
     /*
      * Starts a bugreport in the background.
+     *
+     * @param bugreportFd the file to which the zipped bugreport should be written
+     * @param screenshotFd the file to which screenshot should be written; optional
+     * @param bugreportMode the mode that specifies other run time options; must be one of above
+     * @param listener callback for updates; optional
      */
-    int startBugreport(int fd, int bugreportMode);
+    void startBugreport(FileDescriptor bugreportFd, FileDescriptor screenshotFd, int bugreportMode,
+                        IDumpstateListener listener);
 }
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 030d69d..2966c86 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -22,18 +22,48 @@
   * {@hide}
   */
 interface IDumpstateListener {
+    /**
+     * Called when there is a progress update.
+     *
+     * @param progress the progress in [0, 100]
+     */
+    oneway void onProgress(int progress);
+
+    /* Options specified are invalid or incompatible */
+    const int BUGREPORT_ERROR_INVALID_INPUT = 1;
+
+    /* Bugreport encountered a runtime error */
+    const int BUGREPORT_ERROR_RUNTIME_ERROR = 2;
+
+    /**
+     * Called on an error condition with one of the error codes listed above.
+     */
+    oneway void onError(int errorCode);
+
+    /**
+     * Called when taking bugreport finishes successfully
+     *
+     * @param durationMs time capturing bugreport took in milliseconds
+     * @param title title for the bugreport; helpful in reminding the user why they took it
+     * @param description detailed description for the bugreport
+     */
+     oneway void onFinished(long durationMs, @utf8InCpp String title,
+                            @utf8InCpp String description);
+
+    // TODO(b/111441001): Remove old methods when not used anymore.
     void onProgressUpdated(int progress);
     void onMaxProgressUpdated(int maxProgress);
 
     /**
-    * Called after every section is complete.
-    * @param  name          section name
-    * @param  status        values from status_t
-    *                       {@code OK} section completed successfully
-    *                       {@code TIMEOUT} dump timed out
-    *                       {@code != OK} error
-    * @param  size          size in bytes, may be invalid if status != OK
-    * @param  durationMs    duration in ms
-    */
+     * Called after every section is complete.
+     *
+     * @param  name          section name
+     * @param  status        values from status_t
+     *                       {@code OK} section completed successfully
+     *                       {@code TIMEOUT} dump timed out
+     *                       {@code != OK} error
+     * @param  size          size in bytes, may be invalid if status != OK
+     * @param  durationMs    duration in ms
+     */
     void onSectionComplete(@utf8InCpp String name, int status, int size, int durationMs);
 }
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8a05c43..d42deff 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1701,7 +1701,7 @@
     printf("*** See dumpstate-board.txt entry ***\n");
 }
 
-static void ShowUsageAndExit(int exit_code = 1) {
+static void ShowUsage() {
     fprintf(stderr,
             "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
             "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
@@ -1721,12 +1721,6 @@
             "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
             "shouldn't be used with -P)\n"
             "  -v: prints the dumpstate header and exit\n");
-    exit(exit_code);
-}
-
-static void ExitOnInvalidArgs() {
-    fprintf(stderr, "invalid combination of args\n");
-    ShowUsageAndExit();
 }
 
 static void register_sig_handler() {
@@ -1887,8 +1881,9 @@
     ds.tmp_path_ = ds.GetPath(".tmp");
     ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
 
-    std::string destination = ds.options_->fd != -1 ? StringPrintf("[fd:%d]", ds.options_->fd)
-                                                    : ds.bugreport_dir_.c_str();
+    std::string destination = ds.options_->bugreport_fd.get() != -1
+                                  ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
+                                  : ds.bugreport_dir_.c_str();
     MYLOGD(
         "Bugreport dir: %s\n"
         "Internal Bugreport dir: %s\n"
@@ -1966,8 +1961,8 @@
             }
             // The zip file lives in an internal directory. Copy it over to output.
             bool copy_succeeded = false;
-            if (ds.options_->fd != -1) {
-                copy_succeeded = android::os::CopyFileToFd(ds.path_, ds.options_->fd);
+            if (ds.options_->bugreport_fd.get() != -1) {
+                copy_succeeded = android::os::CopyFileToFd(ds.path_, ds.options_->bugreport_fd.get());
             } else {
                 ds.final_path_ = ds.GetPath(ds.bugreport_dir_, ".zip");
                 copy_succeeded = android::os::CopyFileToFile(ds.path_, ds.final_path_);
@@ -2170,7 +2165,7 @@
     MYLOGI("telephony_only: %d\n", options.telephony_only);
     MYLOGI("wifi_only: %d\n", options.wifi_only);
     MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
-    MYLOGI("fd: %d\n", options.fd);
+    MYLOGI("fd: %d\n", options.bugreport_fd.get());
     MYLOGI("use_outfile: %s\n", options.use_outfile.c_str());
     MYLOGI("extra_options: %s\n", options.extra_options.c_str());
     MYLOGI("args: %s\n", options.args.c_str());
@@ -2178,14 +2173,17 @@
     MYLOGI("notification_description: %s\n", options.notification_description.c_str());
 }
 
-void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode) {
+void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
+                                        const android::base::unique_fd& bugreport_fd_in,
+                                        const android::base::unique_fd& screenshot_fd_in) {
     // In the new API world, date is always added; output is always a zip file.
     // TODO(111441001): remove these options once they are obsolete.
     do_add_date = true;
     do_zip_file = true;
 
-    // STOPSHIP b/111441001: Remove hardcoded output file path; accept fd.
-    use_outfile = "/data/user_de/0/com.android.shell/files/bugreports/bugreport";
+    // Duplicate the fds because the passed in fds don't outlive the binder transaction.
+    bugreport_fd.reset(dup(bugreport_fd_in.get()));
+    screenshot_fd.reset(dup(screenshot_fd_in.get()));
 
     extra_options = ModeToString(bugreport_mode);
     SetOptionsFromMode(bugreport_mode, this);
@@ -2236,11 +2234,11 @@
 }
 
 bool Dumpstate::DumpOptions::ValidateOptions() const {
-    if (fd != -1 && !do_zip_file) {
+    if (bugreport_fd.get() != -1 && !do_zip_file) {
         return false;
     }
 
-    bool has_out_file_options = !use_outfile.empty() || fd != -1;
+    bool has_out_file_options = !use_outfile.empty() || bugreport_fd.get() != -1;
     if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) &&
         !has_out_file_options) {
         return false;
@@ -2264,6 +2262,28 @@
     options_ = std::move(options);
 }
 
+Dumpstate::RunStatus Dumpstate::Run() {
+    Dumpstate::RunStatus status = RunInternal();
+    if (listener_ != nullptr) {
+        switch (status) {
+            case Dumpstate::RunStatus::OK:
+                // TODO(b/111441001): duration argument does not make sense. Remove.
+                listener_->onFinished(0 /* duration */, options_->notification_title,
+                                      options_->notification_description);
+                break;
+            case Dumpstate::RunStatus::HELP:
+                break;
+            case Dumpstate::RunStatus::INVALID_INPUT:
+                listener_->onError(android::os::IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
+                break;
+            case Dumpstate::RunStatus::ERROR:
+                listener_->onError(android::os::IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
+                break;
+        }
+    }
+    return status;
+}
+
 /*
  * Dumps relevant information to a bugreport based on the given options.
  *
@@ -2285,7 +2305,7 @@
  * Bugreports are first generated in a local directory and later copied to the caller's fd or
  * directory.
  */
-Dumpstate::RunStatus Dumpstate::Run() {
+Dumpstate::RunStatus Dumpstate::RunInternal() {
     LogDumpOptions(*options_);
     if (!options_->ValidateOptions()) {
         MYLOGE("Invalid options specified\n");
@@ -2490,6 +2510,7 @@
     /* tell activity manager we're done */
     if (options_->do_broadcast) {
         SendBugreportFinishedBroadcast();
+        // Note that listener_ is notified in Run();
     }
 
     MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
@@ -2523,17 +2544,18 @@
 
     switch (status) {
         case Dumpstate::RunStatus::OK:
-            return 0;
-            // TODO(b/111441001): Exit directly in the following cases.
+            exit(0);
         case Dumpstate::RunStatus::HELP:
-            ShowUsageAndExit(0 /* exit code */);
-            break;
+            ShowUsage();
+            exit(0);
         case Dumpstate::RunStatus::INVALID_INPUT:
-            ExitOnInvalidArgs();
-            break;
+            fprintf(stderr, "Invalid combination of args\n");
+            ShowUsage();
+            exit(1);
         case Dumpstate::RunStatus::ERROR:
-            exit(-1);
-            break;
+            exit(2);
+        default:
+            fprintf(stderr, "Unknown status: %d\n", status);
+            exit(2);
     }
-    return 0;
 }
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 7ac25e4..c620c07 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -342,9 +342,11 @@
         bool wifi_only = false;
         // Whether progress updates should be published.
         bool do_progress_updates = false;
-        // File descriptor to output zip file. -1 indicates not set. Takes precedence over
-        // use_outfile.
-        int fd = -1;
+        // File descriptor to output zip file. Takes precedence over use_outfile.
+        android::base::unique_fd bugreport_fd;
+        // File descriptor to screenshot file.
+        // TODO(b/111441001): Use this fd.
+        android::base::unique_fd screenshot_fd;
         // Partial path to output file.
         std::string use_outfile;
         // TODO: rename to MODE.
@@ -360,7 +362,8 @@
         RunStatus Initialize(int argc, char* argv[]);
 
         /* Initializes options from the requested mode. */
-        void Initialize(BugreportMode bugreport_mode);
+        void Initialize(BugreportMode bugreport_mode, const android::base::unique_fd& bugreport_fd,
+                        const android::base::unique_fd& screenshot_fd);
 
         /* Returns true if the options set so far are consistent. */
         bool ValidateOptions() const;
@@ -446,6 +449,8 @@
     std::vector<DumpData> anr_data_;
 
   private:
+    RunStatus RunInternal();
+
     // Used by GetInstance() only.
     explicit Dumpstate(const std::string& version = VERSION_CURRENT);
 
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 61a5ef5..c57775f 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -53,6 +53,19 @@
     DumpstateListener(int fd, std::shared_ptr<std::vector<SectionInfo>> sections)
         : outFd_(fd), max_progress_(5000), sections_(sections) {
     }
+    binder::Status onProgress(int32_t progress) override {
+        dprintf(outFd_, "\rIn progress %d", progress);
+        return binder::Status::ok();
+    }
+    binder::Status onError(int32_t error_code) override {
+        dprintf(outFd_, "\rError %d", error_code);
+        return binder::Status::ok();
+    }
+    binder::Status onFinished(int64_t duration_ms, const ::std::string&,
+                              const ::std::string&) override {
+        dprintf(outFd_, "\rFinished in %lld", (long long) duration_ms);
+        return binder::Status::ok();
+    }
     binder::Status onProgressUpdated(int32_t progress) override {
         dprintf(outFd_, "\rIn progress %d/%d", progress, max_progress_);
         return binder::Status::ok();
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index fcf9371..cd9b97f 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -59,6 +59,10 @@
 
 class DumpstateListenerMock : public IDumpstateListener {
   public:
+    MOCK_METHOD1(onProgress, binder::Status(int32_t progress));
+    MOCK_METHOD1(onError, binder::Status(int32_t error_code));
+    MOCK_METHOD3(onFinished, binder::Status(int64_t duration_ms, const ::std::string& title,
+                                            const ::std::string& description));
     MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
     MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress));
     MOCK_METHOD4(onSectionComplete, binder::Status(const ::std::string& name, int32_t status,
@@ -652,8 +656,9 @@
         }
 
         if (update_progress) {
-            message += android::base::StringPrintf("Setting progress (%s): %d/%d\n",
-                                                   listener_name.c_str(), progress, max);
+            message += android::base::StringPrintf("Setting progress (%s): %d/%d (%d%%)\n",
+                                                   listener_name.c_str(), progress, max,
+                                                   (100 * progress / max));
         }
 
         return message;
@@ -812,12 +817,14 @@
     SetProgress(0, 30);
 
     EXPECT_CALL(*listener, onProgressUpdated(20));
+    EXPECT_CALL(*listener, onProgress(66));  // 20/30 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
     std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
     EXPECT_THAT(out, StrEq("stdout\n"));
     EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
 
     EXPECT_CALL(*listener, onProgressUpdated(30));
+    EXPECT_CALL(*listener, onProgress(100));  // 35/35 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build()));
     progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
     EXPECT_THAT(out, StrEq("stdout\n"));
@@ -826,6 +833,7 @@
     // Run a command that will increase maximum timeout.
     EXPECT_CALL(*listener, onProgressUpdated(31));
     EXPECT_CALL(*listener, onMaxProgressUpdated(37));
+    EXPECT_CALL(*listener, onProgress(83));  // 31/37 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
     progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30);  // 20% increase
     EXPECT_THAT(out, StrEq("stdout\n"));
@@ -834,6 +842,7 @@
     // Make sure command ran while in dry_run is counted.
     SetDryRun(true);
     EXPECT_CALL(*listener, onProgressUpdated(35));
+    EXPECT_CALL(*listener, onProgress(94));  // 35/37 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
     progress_message = GetProgressMessage(ds.listener_name_, 35, 37);
     EXPECT_THAT(out, IsEmpty());
@@ -850,6 +859,7 @@
 
     // First update should always be sent.
     EXPECT_CALL(*listener, onProgressUpdated(1));
+    EXPECT_CALL(*listener, onProgress(12));  // 1/12 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
     std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 8);
     EXPECT_THAT(out, StrEq("stdout\n"));
@@ -862,6 +872,7 @@
 
     // Third update should be sent because it reaches threshold (6 - 1 = 5).
     EXPECT_CALL(*listener, onProgressUpdated(6));
+    EXPECT_CALL(*listener, onProgress(75));  // 6/8 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
     progress_message = GetProgressMessage(ds.listener_name_, 6, 8);
     EXPECT_THAT(out, StrEq("stdout\n"));
@@ -1101,6 +1112,7 @@
     SetProgress(0, 30);
 
     EXPECT_CALL(*listener, onProgressUpdated(5));
+    EXPECT_CALL(*listener, onProgress(16));  // 5/30 %
     EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
 
     std::string progress_message =
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 990fd43..528e43d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -949,16 +949,22 @@
         fsync(control_socket_fd_);
     }
 
+    int percent = 100 * progress / max;
     if (listener_ != nullptr) {
-        if (progress % 100 == 0) {
-            // We don't want to spam logcat, so only log multiples of 100.
-            MYLOGD("Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
+        if (percent % 5 == 0) {
+            // We don't want to spam logcat, so only log multiples of 5.
+            MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
+                   percent);
         } else {
             // stderr is ignored on normal invocations, but useful when calling
             // /system/bin/dumpstate directly for debuggging.
-            fprintf(stderr, "Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
+            fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
+                    progress, max, percent);
         }
+        // TODO(b/111441001): Remove in favor of onProgress
         listener_->onProgressUpdated(progress);
+
+        listener_->onProgress(percent);
     }
 }
 
diff --git a/cmds/lshal/Command.h b/cmds/lshal/Command.h
index 4f128ab..e19e3f7 100644
--- a/cmds/lshal/Command.h
+++ b/cmds/lshal/Command.h
@@ -27,7 +27,7 @@
 // Base class for all *Commands
 class Command {
 public:
-    Command(Lshal& lshal) : mLshal(lshal) {}
+    explicit Command(Lshal& lshal) : mLshal(lshal) {}
     virtual ~Command() = default;
     // Expect optind to be set by Lshal::main and points to the next argument
     // to process.
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
index 6e12008..3c3f56f 100644
--- a/cmds/lshal/DebugCommand.h
+++ b/cmds/lshal/DebugCommand.h
@@ -31,7 +31,7 @@
 
 class DebugCommand : public Command {
 public:
-    DebugCommand(Lshal &lshal) : Command(lshal) {}
+    explicit DebugCommand(Lshal &lshal) : Command(lshal) {}
     ~DebugCommand() = default;
     Status main(const Arg &arg) override;
     void usage() const override;
diff --git a/cmds/lshal/HelpCommand.h b/cmds/lshal/HelpCommand.h
index cc709f8..da0cba6 100644
--- a/cmds/lshal/HelpCommand.h
+++ b/cmds/lshal/HelpCommand.h
@@ -31,7 +31,7 @@
 
 class HelpCommand : public Command {
 public:
-    HelpCommand(Lshal &lshal) : Command(lshal) {}
+    explicit HelpCommand(Lshal &lshal) : Command(lshal) {}
     ~HelpCommand() = default;
     Status main(const Arg &arg) override;
     void usage() const override;
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index 3f7321d..85195fc 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -57,7 +57,7 @@
 
 class ListCommand : public Command {
 public:
-    ListCommand(Lshal &lshal) : Command(lshal) {}
+    explicit ListCommand(Lshal &lshal) : Command(lshal) {}
     virtual ~ListCommand() = default;
     Status main(const Arg &arg) override;
     void usage() const override;
diff --git a/cmds/lshal/NullableOStream.h b/cmds/lshal/NullableOStream.h
index ab37a04..737d3a2 100644
--- a/cmds/lshal/NullableOStream.h
+++ b/cmds/lshal/NullableOStream.h
@@ -25,8 +25,8 @@
 template<typename S>
 class NullableOStream {
 public:
-    NullableOStream(S &os) : mOs(&os) {}
-    NullableOStream(S *os) : mOs(os) {}
+    explicit NullableOStream(S &os) : mOs(&os) {}
+    explicit NullableOStream(S *os) : mOs(os) {}
     NullableOStream &operator=(S &os) {
         mOs = &os;
         return *this;
@@ -57,7 +57,7 @@
     S& buf() const {
         return *mOs;
     }
-    operator bool() const {
+    operator bool() const { // NOLINT(google-explicit-constructor)
         return mOs != nullptr;
     }
 private:
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 7294b0a..601b7e2 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -149,7 +149,7 @@
 
 class MergedTable {
 public:
-    MergedTable(std::vector<const Table*>&& tables) : mTables(std::move(tables)) {}
+    explicit MergedTable(std::vector<const Table*>&& tables) : mTables(std::move(tables)) {}
     TextTable createTextTable();
 private:
     std::vector<const Table*> mTables;
diff --git a/cmds/lshal/TextTable.h b/cmds/lshal/TextTable.h
index 91d522a..301b4bd 100644
--- a/cmds/lshal/TextTable.h
+++ b/cmds/lshal/TextTable.h
@@ -33,11 +33,11 @@
     TextTableRow() {}
 
     // A row of cells.
-    TextTableRow(std::vector<std::string>&& v) : mFields(std::move(v)) {}
+    explicit TextTableRow(std::vector<std::string>&& v) : mFields(std::move(v)) {}
 
     // A single comment string.
-    TextTableRow(std::string&& s) : mLine(std::move(s)) {}
-    TextTableRow(const std::string& s) : mLine(s) {}
+    explicit TextTableRow(std::string&& s) : mLine(std::move(s)) {}
+    explicit TextTableRow(const std::string& s) : mLine(s) {}
 
     // Whether this row is an actual row of cells.
     bool isRow() const { return !fields().empty(); }
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index 58119a6..46d8177 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -29,7 +29,7 @@
 
 class BackgroundTaskState {
 public:
-    BackgroundTaskState(std::function<void(void)> &&func)
+    explicit BackgroundTaskState(std::function<void(void)> &&func)
             : mFunc(std::forward<decltype(func)>(func)) {}
     void notify() {
         std::unique_lock<std::mutex> lock(mMutex);
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 8d7405b..fc8d58b 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -191,7 +191,7 @@
 // expose protected fields and methods for ListCommand
 class MockListCommand : public ListCommand {
 public:
-    MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
+    explicit MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
 
     Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
     Status main(const Arg& arg) { return ListCommand::main(arg); }
@@ -308,7 +308,7 @@
 // Fake service returned by mocked IServiceManager::get.
 class TestService : public IBase {
 public:
-    TestService(pid_t id) : mId(id) {}
+    explicit TestService(pid_t id) : mId(id) {}
     hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
         cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
         return hardware::Void();
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index a2b4da2..cf3b172 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -154,9 +154,7 @@
 
     // fallback to original method
     if (result != 0) {
-#ifndef VENDORSERVICEMANAGER
         android_errorWriteLog(0x534e4554, "121035042");
-#endif
 
         result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
     }
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index ca004e9..ec3fac5 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -77,11 +77,9 @@
     ad.uid = uid;
     ad.name = name;
 
-#ifndef VENDORSERVICEMANAGER
     if (sid == NULL) {
         android_errorWriteLog(0x534e4554, "121035042");
     }
-#endif
 
     int result = selinux_check_access(sid ? sid : lookup_sid, tctx, class, perm, (void *) &ad);
     allowed = (result == 0);
diff --git a/cmds/surfacereplayer/OWNERS b/cmds/surfacereplayer/OWNERS
new file mode 100644
index 0000000..cc4c842
--- /dev/null
+++ b/cmds/surfacereplayer/OWNERS
@@ -0,0 +1,2 @@
+mathias@google.com
+racarr@google.com
diff --git a/headers/media_plugin/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h
index aa8bd3d..2ed1cca 100644
--- a/headers/media_plugin/media/drm/DrmAPI.h
+++ b/headers/media_plugin/media/drm/DrmAPI.h
@@ -84,6 +84,7 @@
             kDrmPluginEventSessionReclaimed,
             kDrmPluginEventExpirationUpdate,
             kDrmPluginEventKeysChange,
+            kDrmPluginEventSessionLostState,
         };
 
         // Drm keys can be for offline content or for online streaming.
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 05d96ff..d31d1f1 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -112,15 +112,25 @@
 
 #if __ANDROID_API__ >= 29
 
+/**
+ * Possible values of the flags argument to android_res_nsend and android_res_nquery.
+ * Values are ORed together.
+ */
 enum ResNsendFlags : uint32_t {
-    // Send a single request to a single resolver and fail on timeout or network errors
+    /**
+     * Send a single request to a single resolver and fail on timeout or network errors
+     */
     ANDROID_RESOLV_NO_RETRY = 1 << 0,
 
-    // Do not cache the result of the lookup. The lookup may return a result that is already
-    // in the cache, unless the ANDROID_RESOLV_NO_CACHE_LOOKUP flag is also specified.
+    /**
+     * Do not cache the result of the lookup. The lookup may return a result that is already
+     * in the cache, unless the ANDROID_RESOLV_NO_CACHE_LOOKUP flag is also specified.
+     */
     ANDROID_RESOLV_NO_CACHE_STORE = 1 << 1,
 
-    // Don't lookup the request in cache, do not write back the response into the cache
+    /**
+     * Don't lookup the request in cache.
+     */
     ANDROID_RESOLV_NO_CACHE_LOOKUP = 1 << 2,
 };
 
@@ -136,8 +146,7 @@
  * POSIX error code (see errno.h) if an immediate error occurs.
  */
 int android_res_nquery(net_handle_t network,
-        const char *dname, int ns_class, int ns_type,
-        enum ResNsendFlags flags) __INTRODUCED_IN(29);
+        const char *dname, int ns_class, int ns_type, uint32_t flags) __INTRODUCED_IN(29);
 
 /**
  * Issue the query |msg| on the given |network|.
@@ -148,10 +157,11 @@
  * POSIX error code (see errno.h) if an immediate error occurs.
  */
 int android_res_nsend(net_handle_t network,
-        const uint8_t *msg, size_t msglen, enum ResNsendFlags flags) __INTRODUCED_IN(29);
+        const uint8_t *msg, size_t msglen, uint32_t flags) __INTRODUCED_IN(29);
 
 /**
  * Read a result for the query associated with the |fd| descriptor.
+ * Closes |fd| before returning.
  *
  * Returns:
  *     < 0: negative POSIX error code (see errno.h for possible values). |rcode| is not set.
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 005564d..1a1b010 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -64,6 +64,7 @@
 #define ASENSOR_RESOLUTION_INVALID     (nanf(""))
 #define ASENSOR_FIFO_COUNT_INVALID     (-1)
 #define ASENSOR_DELAY_INVALID          INT32_MIN
+#define ASENSOR_INVALID                (-1)
 
 /* (Keep in sync with hardware/sensors-base.h and Sensor.java.) */
 
@@ -208,6 +209,35 @@
      */
     ASENSOR_TYPE_HEART_BEAT = 31,
     /**
+     * This sensor type is for delivering additional sensor information aside
+     * from sensor event data.
+     *
+     * Additional information may include:
+     *     - {@link ASENSOR_ADDITIONAL_INFO_INTERNAL_TEMPERATURE}
+     *     - {@link ASENSOR_ADDITIONAL_INFO_SAMPLING}
+     *     - {@link ASENSOR_ADDITIONAL_INFO_SENSOR_PLACEMENT}
+     *     - {@link ASENSOR_ADDITIONAL_INFO_UNTRACKED_DELAY}
+     *     - {@link ASENSOR_ADDITIONAL_INFO_VEC3_CALIBRATION}
+     *
+     * This type will never bind to a sensor. In other words, no sensor in the
+     * sensor list can have the type {@link ASENSOR_TYPE_ADDITIONAL_INFO}.
+     *
+     * If a device supports the sensor additional information feature, it will
+     * report additional information events via {@link ASensorEvent} and will
+     * have {@link ASensorEvent#type} set to
+     * {@link ASENSOR_TYPE_ADDITIONAL_INFO} and {@link ASensorEvent#sensor} set
+     * to the handle of the reporting sensor.
+     *
+     * Additional information reports consist of multiple frames ordered by
+     * {@link ASensorEvent#timestamp}. The first frame in the report will have
+     * a {@link AAdditionalInfoEvent#type} of
+     * {@link ASENSOR_ADDITIONAL_INFO_BEGIN}, and the last frame in the report
+     * will have a {@link AAdditionalInfoEvent#type} of
+     * {@link ASENSOR_ADDITIONAL_INFO_END}.
+     *
+     */
+    ASENSOR_TYPE_ADDITIONAL_INFO = 33,
+    /**
      * {@link ASENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT}
      */
     ASENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT = 34,
@@ -273,6 +303,51 @@
     ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER = 2
 };
 
+/**
+ * Sensor Additional Info Types.
+ *
+ * Used to populate {@link AAdditionalInfoEvent#type}.
+ */
+enum {
+    /** Marks the beginning of additional information frames */
+    ASENSOR_ADDITIONAL_INFO_BEGIN = 0,
+
+    /** Marks the end of additional information frames */
+    ASENSOR_ADDITIONAL_INFO_END = 1,
+
+    /**
+     * Estimation of the delay that is not tracked by sensor timestamps. This
+     * includes delay introduced by sensor front-end filtering, data transport,
+     * etc.
+     * float[2]: delay in seconds, standard deviation of estimated value
+     */
+    ASENSOR_ADDITIONAL_INFO_UNTRACKED_DELAY = 0x10000,
+
+    /** float: Celsius temperature */
+    ASENSOR_ADDITIONAL_INFO_INTERNAL_TEMPERATURE,
+
+    /**
+     * First three rows of a homogeneous matrix, which represents calibration to
+     * a three-element vector raw sensor reading.
+     * float[12]: 3x4 matrix in row major order
+     */
+    ASENSOR_ADDITIONAL_INFO_VEC3_CALIBRATION,
+
+    /**
+     * Location and orientation of sensor element in the device frame: origin is
+     * the geometric center of the mobile device screen surface; the axis
+     * definition corresponds to Android sensor definitions.
+     * float[12]: 3x4 matrix in row major order
+     */
+    ASENSOR_ADDITIONAL_INFO_SENSOR_PLACEMENT,
+
+    /**
+     * float[2]: raw sample period in seconds,
+     *           standard deviation of sampling period
+     */
+    ASENSOR_ADDITIONAL_INFO_SAMPLING,
+};
+
 /*
  * A few useful constants
  */
@@ -341,7 +416,7 @@
     int32_t  handle;
 } ADynamicSensorEvent;
 
-typedef struct {
+typedef struct AAdditionalInfoEvent {
     int32_t type;
     int32_t serial;
     union {
@@ -444,6 +519,7 @@
  * - ASensor_getStringType()
  * - ASensor_getReportingMode()
  * - ASensor_isWakeUpSensor()
+ * - ASensor_getHandle()
  */
 typedef struct ASensor ASensor;
 /**
@@ -785,6 +861,24 @@
 int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_IN(26);
 #endif /* __ANDROID_API__ >= 26 */
 
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+/**
+ * Returns the sensor's handle.
+ *
+ * The handle identifies the sensor within the system and is included in the
+ * {@link ASensorEvent#sensor} field of sensor events, including those sent with type
+ * {@link ASENSOR_TYPE_ADDITIONAL_INFO}.
+ *
+ * A sensor's handle is able to be used to map {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to the
+ * sensor that generated the event.
+ *
+ * It is important to note that the value returned by {@link ASensor_getHandle} is not the same as
+ * the value returned by the Java API {@link android.hardware.Sensor#getId} and no mapping exists
+ * between the values.
+ */
+int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(__ANDROID_API_Q__);
+#endif /* __ANDROID_API__ >= ANDROID_API_Q__ */
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
new file mode 100644
index 0000000..13b630b
--- /dev/null
+++ b/include/android/surface_control.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NativeActivity Native Activity
+ * @{
+ */
+
+/**
+ * @file surface_control.h
+ */
+
+#ifndef ANDROID_SURFACE_CONTROL_H
+#define ANDROID_SURFACE_CONTROL_H
+
+#include <sys/cdefs.h>
+
+#include <android/hardware_buffer.h>
+#include <android/native_window.h>
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= 29
+
+struct ASurfaceControl;
+
+/**
+ * The SurfaceControl API can be used to provide a heirarchy of surfaces for
+ * composition to the system compositor. ASurfaceControl represents a content node in
+ * this heirarchy.
+ */
+typedef struct ASurfaceControl ASurfaceControl;
+
+/*
+ * Creates an ASurfaceControl with either ANativeWindow or an ASurfaceControl as its parent.
+ * |debug_name| is a debug name associated with this surface. It can be used to
+ * identify this surface in the SurfaceFlinger's layer tree. It must not be
+ * null.
+ *
+ * The caller takes ownership of the ASurfaceControl returned and must release it
+ * using ASurfaceControl_release below.
+ */
+ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* parent, const char* debug_name)
+                                                  __INTRODUCED_IN(29);
+
+ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name)
+                                        __INTRODUCED_IN(29);
+
+/**
+ * Destroys the |surface_control| object. After releasing the ASurfaceControl the caller no longer
+ * has ownership of the AsurfaceControl.
+ */
+void ASurfaceControl_destroy(ASurfaceControl* surface_control) __INTRODUCED_IN(29);
+
+struct ASurfaceTransaction;
+
+/**
+ * ASurfaceTransaction is a collection of updates to the surface tree that must
+ * be applied atomically.
+ */
+typedef struct ASurfaceTransaction ASurfaceTransaction;
+
+/**
+ * The caller takes ownership of the transaction and must release it using
+ * ASurfaceControl_delete below.
+ */
+ASurfaceTransaction* ASurfaceTransaction_create() __INTRODUCED_IN(29);
+
+/**
+ * Destroys the |transaction| object.
+ */
+void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
+
+/**
+ * Applies the updates accumulated in |transaction|.
+ *
+ * Note that the transaction is guaranteed to be applied atomically. The
+ * transactions which are applied on the same thread are also guaranteed to be
+ * applied in order.
+ */
+void ASurfaceTransaction_apply(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
+
+/**
+ * Since the transactions are applied asynchronously, the
+ * ASurfaceTransaction_OnComplete callback can be used to be notified when a frame
+ * including the updates in a transaction was presented.
+ *
+ * |context| is the optional context provided by the client that is passed into
+ * the callback.
+ * |present_fence| is the sync fence that signals when the transaction has been presented.
+ * The recipient of the callback takes ownership of the present_fence and is responsible for closing
+ * it.
+ *
+ * It is safe to assume that once the present fence singals, that reads for all buffers,
+ * submitted in previous transactions, which are not in the surface tree after a transaction is
+ * applied, are finished and the buffers may be reused.
+ *
+ * THREADING
+ * The transaction completed callback can be invoked on any thread.
+ */
+typedef void (*ASurfaceTransaction_OnComplete)(void* context, int32_t present_fence);
+
+/**
+ * Sets the callback that will be invoked when the updates from this transaction
+ * are presented. For details on the callback semantics and data, see the
+ * comments on the ASurfaceTransaction_OnComplete declaration above.
+ */
+void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* context,
+                                       ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29);
+
+/* Parameter for ASurfaceTransaction_setVisibility */
+enum {
+    ASURFACE_TRANSACTION_VISIBILITY_HIDE = 0,
+    ASURFACE_TRANSACTION_VISIBILITY_SHOW = 1,
+};
+/**
+ * Updates the visibility of |surface_control|. If show is set to
+ * ASURFACE_TRANSACTION_VISIBILITY_HIDE, the |surface_control| and all surfaces in its subtree will
+ * be hidden.
+ */
+void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction,
+                                       ASurfaceControl* surface_control, int8_t visibility)
+                                       __INTRODUCED_IN(29);
+
+/**
+ * Updates the z order index for |surface_control|. Note that the z order for a surface
+ * is relative to other surfaces which are siblings of this surface. The behavior of sibilings with
+ * the same z order is undefined.
+ *
+ * Z orders may be from MIN_INT32 to MAX_INT32. A layer's default z order index is 0.
+ */
+void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction,
+                                   ASurfaceControl* surface_control, int32_t z_order)
+                                   __INTRODUCED_IN(29);
+
+/**
+ * Updates the AHardwareBuffer displayed for |surface_control|. If not -1, the
+ * fence_fd should be a file descriptor that is signaled when all pending work
+ * for the buffer is complete and the buffer can be safely read.
+ *
+ * The frameworks takes ownership of the |fence_fd| passed and is responsible
+ * for closing it.
+ */
+void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction,
+                                   ASurfaceControl* surface_control, AHardwareBuffer* buffer,
+                                   int fence_fd = -1) __INTRODUCED_IN(29);
+
+/**
+ * |source| the sub-rect within the buffer's content to be rendered inside the surface's area
+ * The surface's source rect is clipped by the bounds of its current buffer. The source rect's width
+ * and height must be > 0.
+ *
+ * |destination| specifies the rect in the parent's space where this surface will be drawn. The post
+ * source rect bounds are scaled to fit the destination rect. The surface's destination rect is
+ * clipped by the bounds of its parent. The destination rect's width and height must be > 0.
+ *
+ * |transform| the transform applied after the source rect is applied to the buffer. This parameter
+ * should be set to 0 for no transform. To specify a transfrom use the NATIVE_WINDOW_TRANSFORM_*
+ * enum.
+ */
+void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction,
+                                     ASurfaceControl* surface_control, const ARect& source,
+                                     const ARect& destination, int32_t transform)
+                                     __INTRODUCED_IN(29);
+
+
+/* Parameter for ASurfaceTransaction_setBufferTransparency */
+enum {
+    ASURFACE_TRANSACTION_TRANSPARENCY_TRANSPARENT = 0,
+    ASURFACE_TRANSACTION_TRANSPARENCY_TRANSLUCENT = 1,
+    ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE = 2,
+};
+/**
+ * Updates whether the content for the buffer associated with this surface is
+ * completely opaque. If true, every pixel of content inside the buffer must be
+ * opaque or visual errors can occur.
+ */
+void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* transaction,
+                                         ASurfaceControl* surface_control, int8_t transparency)
+                                         __INTRODUCED_IN(29);
+
+/**
+ * Updates the region for the content on this surface updated in this
+ * transaction. If unspecified, the complete surface is assumed to be damaged.
+ */
+void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* transaction,
+                                         ASurfaceControl* surface_control, const ARect rects[],
+                                         uint32_t count) __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+__END_DECLS
+
+#endif // ANDROID_SURFACE_CONTROL_H
diff --git a/include/input/Input.h b/include/input/Input.h
index 037270c..2c4a511 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -220,6 +220,27 @@
     POLICY_FLAG_PASS_TO_USER = 0x40000000,
 };
 
+/**
+ * Classifications of the current gesture, if available.
+ *
+ * The following values must be kept in sync with MotionEvent.java
+ */
+enum class MotionClassification : uint8_t {
+    /**
+     * No classification is available.
+     */
+    NONE = 0,
+    /**
+     * Too early to classify the current gesture. Need more events. Look for changes in the
+     * upcoming motion events.
+     */
+    AMBIGUOUS_GESTURE = 1,
+    /**
+     * The current gesture likely represents a user intentionally exerting force on the touchscreen.
+     */
+    DEEP_PRESS = 2,
+};
+
 /*
  * Pointer coordinate data.
  */
@@ -419,6 +440,8 @@
 
     inline void setButtonState(int32_t buttonState) { mButtonState = buttonState; }
 
+    inline MotionClassification getClassification() const { return mClassification; }
+
     inline int32_t getActionButton() const { return mActionButton; }
 
     inline void setActionButton(int32_t button) { mActionButton = button; }
@@ -582,6 +605,7 @@
             int32_t edgeFlags,
             int32_t metaState,
             int32_t buttonState,
+            MotionClassification classification,
             float xOffset,
             float yOffset,
             float xPrecision,
@@ -635,6 +659,7 @@
     int32_t mEdgeFlags;
     int32_t mMetaState;
     int32_t mButtonState;
+    MotionClassification mClassification;
     float mXOffset;
     float mYOffset;
     float mXPrecision;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 14a801c..9a561cb 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -23,7 +23,9 @@
 #include <binder/BpBinder.h>
 #include <binder/TextOutput.h>
 
+#include <android-base/macros.h>
 #include <cutils/sched_policy.h>
+#include <utils/CallStack.h>
 #include <utils/Log.h>
 #include <utils/SystemClock.h>
 #include <utils/threads.h>
@@ -670,6 +672,16 @@
     }
 
     if ((flags & TF_ONE_WAY) == 0) {
+        if (UNLIKELY(mCallRestriction != ProcessState::CallRestriction::NONE)) {
+            if (mCallRestriction == ProcessState::CallRestriction::ERROR_IF_NOT_ONEWAY) {
+                ALOGE("Process making non-oneway call but is restricted.");
+                CallStack::logStack("non-oneway call", CallStack::getCurrent(10).get(),
+                    ANDROID_LOG_ERROR);
+            } else /* FATAL_IF_NOT_ONEWAY */ {
+                LOG_ALWAYS_FATAL("Process may not make oneway calls.");
+            }
+        }
+
         #if 0
         if (code == 4) { // relayout
             ALOGI(">>>>>> CALLING transaction 4");
@@ -792,7 +804,8 @@
       mWorkSource(kUnsetWorkSource),
       mPropagateWorkSource(false),
       mStrictModePolicy(0),
-      mLastTransactionBinderFlags(0)
+      mLastTransactionBinderFlags(0),
+      mCallRestriction(mProcess->mCallRestriction)
 {
     pthread_setspecific(gTLS, this);
     clearCaller();
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index b060288..79db0cb 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -246,6 +246,12 @@
     return count;
 }
 
+void ProcessState::setCallRestriction(CallRestriction restriction) {
+    LOG_ALWAYS_FATAL_IF(IPCThreadState::selfOrNull(), "Call restrictions must be set before the threadpool is started.");
+
+    mCallRestriction = restriction;
+}
+
 ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
 {
     const size_t N=mHandleToObject.size();
@@ -438,6 +444,7 @@
     , mBinderContextUserData(nullptr)
     , mThreadPoolStarted(false)
     , mThreadPoolSeq(1)
+    , mCallRestriction(CallRestriction::NONE)
 {
     if (mDriverFD >= 0) {
         // mmap the binder, providing a chunk of virtual address space to receive transactions.
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 5ec02b1..f6381f7 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -124,7 +124,9 @@
 
 
 #define CHECK_INTERFACE(interface, data, reply)                         \
-    if (!(data).checkInterface(this)) { return PERMISSION_DENIED; }     \
+    do {                                                                \
+      if (!(data).checkInterface(this)) { return PERMISSION_DENIED; }   \
+    } while (false)                                                     \
 
 
 // ----------------------------------------------------------------------
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index adc7e5f..614b0b3 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -190,6 +190,8 @@
             int32_t             mStrictModePolicy;
             int32_t             mLastTransactionBinderFlags;
             IPCThreadStateBase  *mIPCThreadStateBase;
+
+            ProcessState::CallRestriction mCallRestriction;
 };
 
 }; // namespace android
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 3712c84..224cb36 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -77,6 +77,18 @@
 
             ssize_t             getKernelReferences(size_t count, uintptr_t* buf);
 
+            enum class CallRestriction {
+                // all calls okay
+                NONE,
+                // log when calls are blocking
+                ERROR_IF_NOT_ONEWAY,
+                // abort process on blocking calls
+                FATAL_IF_NOT_ONEWAY,
+            };
+            // Sets calling restrictions for all transactions in this process. This must be called
+            // before any threads are spawned.
+            void setCallRestriction(CallRestriction restriction);
+
 private:
     friend class IPCThreadState;
     
@@ -123,6 +135,8 @@
             String8             mRootDir;
             bool                mThreadPoolStarted;
     volatile int32_t            mThreadPoolSeq;
+
+            CallRestriction     mCallRestriction;
 };
     
 }; // namespace android
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 1b69dfd..05655c1 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -23,7 +23,11 @@
         "include_apex",
     ],
 
-    cflags: ["-Wall", "-Wextra", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
 
     srcs: [
         "ibinder.cpp",
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index ee7132f..f0d25f7 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -87,6 +87,11 @@
     AStatus_getStatus;
     AStatus_isOk;
     AStatus_newOk;
+    ABinderProcess_joinThreadPool; # apex
+    ABinderProcess_setThreadPoolMaxThreadCount; # apex
+    ABinderProcess_startThreadPool; # apex
+    AServiceManager_addService; # apex
+    AServiceManager_getService; # apex
   local:
     *;
 };
diff --git a/libs/binder/ndk/scripts/init_map.sh b/libs/binder/ndk/scripts/init_map.sh
index 1f74e43..3529b72 100755
--- a/libs/binder/ndk/scripts/init_map.sh
+++ b/libs/binder/ndk/scripts/init_map.sh
@@ -10,6 +10,10 @@
     grep -oP "AParcel_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_parcel.h;
     grep -oP "AStatus_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_status.h;
 } | sort | uniq | awk '{ print "    " $0 ";"; }'
+{
+    grep -oP "AServiceManager_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_manager.h;
+    grep -oP "ABinderProcess_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_process.h;
+} | sort | uniq | awk '{ print "    " $0 "; # apex"; }'
 echo "  local:"
 echo "    *;"
 echo "};"
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 37c24ef..429ce0e 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -24,7 +24,7 @@
 
 namespace android {
 
-class NativeLoaderNamespace;
+struct NativeLoaderNamespace;
 
 class GraphicsEnv {
 public:
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index d1c732b..3521e89 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -121,6 +121,7 @@
     ],
 
     shared_libs: [
+        "android.frameworks.bufferhub@1.0",
         "android.hardware.graphics.common@1.1",
         "libbase",
         "libsync",
@@ -153,6 +154,7 @@
                 "BufferHubProducer.cpp",
             ],
             exclude_shared_libs: [
+                "android.frameworks.bufferhub@1.0",
                 "libbufferhub",
                 "libbufferhubqueue",
                 "libpdx_default_transport",
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index a481e81..7357ba9 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -681,6 +681,18 @@
         result = reply.readUint64Vector(&outStats->component_3_sample);
         return result;
     }
+
+    virtual status_t getProtectedContentSupport(bool* outSupported) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT, data, &reply);
+        bool result;
+        status_t err = reply.readBool(&result);
+        if (err == NO_ERROR) {
+            *outSupported = result;
+        }
+        return err;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -1017,7 +1029,7 @@
                 reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
                 reply->writeInt32(static_cast<int32_t>(wideColorGamutPixelFormat));
             }
-            return NO_ERROR;
+            return error;
         }
         case GET_COLOR_MANAGEMENT: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -1026,7 +1038,7 @@
             if (error == NO_ERROR) {
                 reply->writeBool(result);
             }
-            return result;
+            return error;
         }
         case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -1110,6 +1122,15 @@
             }
             return result;
         }
+        case GET_PROTECTED_CONTENT_SUPPORT: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            bool result;
+            status_t error = getProtectedContentSupport(&result);
+            if (error == NO_ERROR) {
+                reply->writeBool(result);
+            }
+            return error;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 369f523..928ef95 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -31,6 +31,7 @@
 
 enum class Tag : uint32_t {
     CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
+    CREATE_WITH_SURFACE_PARENT,
     CLEAR_LAYER_FRAME_STATS,
     GET_LAYER_FRAME_STATS,
     LAST = GET_LAYER_FRAME_STATS,
@@ -56,6 +57,18 @@
                                                                             handle, gbp);
     }
 
+    status_t createWithSurfaceParent(const String8& name, uint32_t width, uint32_t height,
+                                     PixelFormat format, uint32_t flags,
+                                     const sp<IGraphicBufferProducer>& parent, int32_t windowType,
+                                     int32_t ownerUid, sp<IBinder>* handle,
+                                     sp<IGraphicBufferProducer>* gbp) override {
+        return callRemote<decltype(
+                &ISurfaceComposerClient::createWithSurfaceParent)>(Tag::CREATE_WITH_SURFACE_PARENT,
+                                                                   name, width, height, format,
+                                                                   flags, parent, windowType,
+                                                                   ownerUid, handle, gbp);
+    }
+
     status_t clearLayerFrameStats(const sp<IBinder>& handle) const override {
         return callRemote<decltype(
                 &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::CLEAR_LAYER_FRAME_STATS,
@@ -86,6 +99,8 @@
     switch (tag) {
         case Tag::CREATE_SURFACE:
             return callLocal(data, reply, &ISurfaceComposerClient::createSurface);
+        case Tag::CREATE_WITH_SURFACE_PARENT:
+            return callLocal(data, reply, &ISurfaceComposerClient::createWithSurfaceParent);
         case Tag::CLEAR_LAYER_FRAME_STATS:
             return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
         case Tag::GET_LAYER_FRAME_STATS:
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 1be55e6..ce88d7b 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -39,7 +39,16 @@
     if (err != NO_ERROR) {
         return err;
     }
-    return output->writeBool(releasePreviousBuffer);
+    if (previousReleaseFence) {
+        err = output->writeBool(true);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        err = output->write(*previousReleaseFence);
+    } else {
+        err = output->writeBool(false);
+    }
+    return err;
 }
 
 status_t SurfaceStats::readFromParcel(const Parcel* input) {
@@ -51,7 +60,19 @@
     if (err != NO_ERROR) {
         return err;
     }
-    return input->readBool(&releasePreviousBuffer);
+    bool hasFence = false;
+    err = input->readBool(&hasFence);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    if (hasFence) {
+        previousReleaseFence = new Fence();
+        err = input->read(*previousReleaseFence);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+    return NO_ERROR;
 }
 
 status_t TransactionStats::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index a7c7e79..73150dc 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,8 +1,7 @@
-brianderson@google.com
 jessehall@google.com
 jwcai@google.com
+lpy@google.com
+marissaw@google.com
 mathias@google.com
-olv@google.com
-pceballos@google.com
 racarr@google.com
 stoza@google.com
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6c39d6f..e3ee511 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -977,6 +977,29 @@
     return s;
 }
 
+sp<SurfaceControl> SurfaceComposerClient::createWithSurfaceParent(const String8& name, uint32_t w,
+                                                                  uint32_t h, PixelFormat format,
+                                                                  uint32_t flags, Surface* parent,
+                                                                  int32_t windowType,
+                                                                  int32_t ownerUid) {
+    sp<SurfaceControl> sur;
+    status_t err = mStatus;
+
+    if (mStatus == NO_ERROR) {
+        sp<IBinder> handle;
+        sp<IGraphicBufferProducer> parentGbp = parent->getIGraphicBufferProducer();
+        sp<IGraphicBufferProducer> gbp;
+
+        err = mClient->createWithSurfaceParent(name, w, h, format, flags, parentGbp, windowType,
+                                               ownerUid, &handle, &gbp);
+        ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err));
+        if (err == NO_ERROR) {
+            return new SurfaceControl(this, handle, gbp, true /* owned */);
+        }
+    }
+    return nullptr;
+}
+
 status_t SurfaceComposerClient::createSurfaceChecked(
         const String8& name,
         uint32_t w,
@@ -1095,6 +1118,12 @@
                                        wideColorGamutDataspace, wideColorGamutPixelFormat);
 }
 
+bool SurfaceComposerClient::getProtectedContentSupport() {
+    bool supported = false;
+    ComposerService::getComposerService()->getProtectedContentSupport(&supported);
+    return supported;
+}
+
 status_t SurfaceComposerClient::clearAnimationFrameStats() {
     return ComposerService::getComposerService()->clearAnimationFrameStats();
 }
@@ -1132,6 +1161,7 @@
     return ComposerService::getComposerService()->getDisplayedContentSample(display, maxFrames,
                                                                             timestamp, outStats);
 }
+
 // ----------------------------------------------------------------------------
 
 status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 537c957..b377a41 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -40,13 +40,14 @@
 #define BQ_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
 #define BQ_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
 
-#define ATRACE_BUFFER_INDEX(index)                                   \
-    if (ATRACE_ENABLED()) {                                          \
-        char ___traceBuf[1024];                                      \
-        snprintf(___traceBuf, 1024, "%s: %d",                        \
-                mCore->mConsumerName.string(), (index));             \
-        android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);  \
-    }
+#define ATRACE_BUFFER_INDEX(index)                                                         \
+    do {                                                                                   \
+        if (ATRACE_ENABLED()) {                                                            \
+            char ___traceBuf[1024];                                                        \
+            snprintf(___traceBuf, 1024, "%s: %d", mCore->mConsumerName.string(), (index)); \
+            android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);                    \
+        }                                                                                  \
+    } while (false)
 
 namespace android {
 
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 1534fca..9812e1c 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -309,6 +309,12 @@
     virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
                                                uint64_t timestamp,
                                                DisplayedFrameStats* outStats) const = 0;
+
+    /*
+     * Gets whether SurfaceFlinger can support protected content in GPU composition.
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -350,6 +356,7 @@
         GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
         SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
         GET_DISPLAYED_CONTENT_SAMPLE,
+        GET_PROTECTED_CONTENT_SUPPORT,
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 56ca197..f443df8 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -58,6 +58,16 @@
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
      */
+    virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+                                             PixelFormat format, uint32_t flags,
+                                             const sp<IGraphicBufferProducer>& parent,
+                                             int32_t windowType, int32_t ownerUid,
+                                             sp<IBinder>* handle,
+                                             sp<IGraphicBufferProducer>* gbp) = 0;
+
+    /*
+     * Requires ACCESS_SURFACE_FLINGER permission
+     */
     virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const = 0;
 
     /*
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 8acfa7a..29ab026 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -52,12 +52,12 @@
     status_t readFromParcel(const Parcel* input) override;
 
     SurfaceStats() = default;
-    SurfaceStats(const sp<IBinder>& sc, nsecs_t time, bool releasePrevBuffer)
-          : surfaceControl(sc), acquireTime(time), releasePreviousBuffer(releasePrevBuffer) {}
+    SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence)
+          : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {}
 
     sp<IBinder> surfaceControl;
     nsecs_t acquireTime = -1;
-    bool releasePreviousBuffer = false;
+    sp<Fence> previousReleaseFence;
 };
 
 class TransactionStats : public Parcelable {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e0cbb70..9a4f7a0 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -145,6 +145,12 @@
                                              ui::Dataspace* wideColorGamutDataspace,
                                              ui::PixelFormat* wideColorGamutPixelFormat);
 
+    /*
+     * Gets whether SurfaceFlinger can support protected content in GPU composition.
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    static bool getProtectedContentSupport();
+
     /**
      * Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it
      * to null), but without needing an sp<SurfaceControl> to avoid infinite ressurection.
@@ -168,15 +174,27 @@
     );
 
     status_t createSurfaceChecked(
-            const String8& name,// name of the surface
-            uint32_t w,         // width in pixel
-            uint32_t h,         // height in pixel
-            PixelFormat format, // pixel-format desired
+            const String8& name, // name of the surface
+            uint32_t w,          // width in pixel
+            uint32_t h,          // height in pixel
+            PixelFormat format,  // pixel-format desired
             sp<SurfaceControl>* outSurface,
-            uint32_t flags = 0, // usage flags
+            uint32_t flags = 0,               // usage flags
             SurfaceControl* parent = nullptr, // parent
             int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
-            int32_t ownerUid = -1 // UID of the task
+            int32_t ownerUid = -1    // UID of the task
+    );
+
+    //! Create a surface
+    sp<SurfaceControl> createWithSurfaceParent(
+            const String8& name,       // name of the surface
+            uint32_t w,                // width in pixel
+            uint32_t h,                // height in pixel
+            PixelFormat format,        // pixel-format desired
+            uint32_t flags = 0,        // usage flags
+            Surface* parent = nullptr, // parent
+            int32_t windowType = -1,   // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
+            int32_t ownerUid = -1      // UID of the task
     );
 
     //! Create a virtual display
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 60173dc..2d773f2 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -655,7 +655,8 @@
         return NO_ERROR;
     }
 
-    virtual status_t getColorManagement(bool* /*outGetColorManagement*/) const { return NO_ERROR; }
+    status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
+    status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
 
 protected:
     IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index a558970..db86c8e 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -234,6 +234,7 @@
         int32_t edgeFlags,
         int32_t metaState,
         int32_t buttonState,
+        MotionClassification classification,
         float xOffset,
         float yOffset,
         float xPrecision,
@@ -250,6 +251,7 @@
     mEdgeFlags = edgeFlags;
     mMetaState = metaState;
     mButtonState = buttonState;
+    mClassification = classification;
     mXOffset = xOffset;
     mYOffset = yOffset;
     mXPrecision = xPrecision;
@@ -270,6 +272,7 @@
     mEdgeFlags = other->mEdgeFlags;
     mMetaState = other->mMetaState;
     mButtonState = other->mButtonState;
+    mClassification = other->mClassification;
     mXOffset = other->mXOffset;
     mYOffset = other->mYOffset;
     mXPrecision = other->mXPrecision;
@@ -451,6 +454,7 @@
     mEdgeFlags = parcel->readInt32();
     mMetaState = parcel->readInt32();
     mButtonState = parcel->readInt32();
+    mClassification = static_cast<MotionClassification>(parcel->readByte());
     mXOffset = parcel->readFloat();
     mYOffset = parcel->readFloat();
     mXPrecision = parcel->readFloat();
@@ -501,6 +505,7 @@
     parcel->writeInt32(mEdgeFlags);
     parcel->writeInt32(mMetaState);
     parcel->writeInt32(mButtonState);
+    parcel->writeByte(static_cast<int8_t>(mClassification));
     parcel->writeFloat(mXOffset);
     parcel->writeFloat(mYOffset);
     parcel->writeFloat(mXPrecision);
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index f33b210..0ddee44 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -1112,6 +1112,7 @@
             msg->body.motion.edgeFlags,
             msg->body.motion.metaState,
             msg->body.motion.buttonState,
+            MotionClassification::NONE,
             msg->body.motion.xOffset,
             msg->body.motion.yOffset,
             msg->body.motion.xPrecision,
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 99f83ba..e4c1514 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -260,7 +260,7 @@
     event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0,
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
             AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
-            X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
+            MotionClassification::NONE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
             ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
             2, pointerProperties, pointerCoords);
 
@@ -572,8 +572,11 @@
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
     }
     MotionEvent event;
-    event.initialize(0, 0, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
+    event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
+            0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE,
+            AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+            0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+            0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
     float originalRawX = 0 + 3;
     float originalRawY = -RADIUS + 2;
 
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index af97c34..3c67542 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -90,7 +90,8 @@
 
     MotionEvent* event = new MotionEvent();
     PointerCoords coords;
-    PointerProperties properties[1];
+    constexpr size_t pointerCount = 1;
+    PointerProperties properties[pointerCount];
 
     properties[0].id = DEFAULT_POINTER_ID;
     properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
@@ -98,8 +99,11 @@
     // First sample added separately with initialize
     coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x);
     coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y);
-    event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, positions[0].time, 1, properties, &coords);
+    event->initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/,
+            AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+            0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+            0 /*downTime*/, positions[0].time, pointerCount, properties, &coords);
 
     for (size_t i = 1; i < numSamples; i++) {
         coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[i].x);
diff --git a/libs/math/OWNERS b/libs/math/OWNERS
new file mode 100644
index 0000000..6fb149a
--- /dev/null
+++ b/libs/math/OWNERS
@@ -0,0 +1,6 @@
+jaesoo@google.com
+jiyong@google.com
+mathias@google.com
+pawin@google.com
+randolphs@google.com
+romainguy@google.com
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
index 1da79a0..f973cba 100644
--- a/libs/sensorprivacy/SensorPrivacyManager.cpp
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -85,4 +85,22 @@
     return false;
 }
 
+status_t SensorPrivacyManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        return IInterface::asBinder(service)->linkToDeath(recipient);
+    }
+    return INVALID_OPERATION;
+}
+
+status_t SensorPrivacyManager::unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        return IInterface::asBinder(service)->unlinkToDeath(recipient);
+    }
+    return INVALID_OPERATION;
+}
+
 }; // namespace android
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
index 8826595..2546a68 100644
--- a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -34,6 +34,9 @@
     void removeSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
     bool isSensorPrivacyEnabled();
 
+    status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+    status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+
 private:
     Mutex mLock;
     sp<hardware::ISensorPrivacyManager> mService;
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 956465c..d089bf6 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -77,6 +77,7 @@
     ],
 
     shared_libs: [
+        "android.frameworks.bufferhub@1.0",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@2.0",
@@ -93,7 +94,6 @@
         "libutils",
         "libutilscallstack",
         "liblog",
-        "libpdx_default_transport",  // TODO(b/112338294): Remove this once BufferHub moved to use Binder.
     ],
 
     export_shared_lib_headers: [
@@ -121,6 +121,7 @@
                 "libnativewindow_headers",
             ],
             exclude_shared_libs: [
+                "android.frameworks.bufferhub@1.0",
                 "libpdx_default_transport",
             ],
         },
@@ -148,9 +149,6 @@
         "libhardware_headers",
         "libui_headers",
     ],
-
-    // TODO(b/117568153): Temporarily opt out using libcrt.
-    no_libcrt: true,
 }
 
 cc_library_headers {
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 1184960..6310f29 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -14,150 +14,190 @@
  * limitations under the License.
  */
 
-// We would eliminate the clang warnings introduced by libdpx.
-// TODO(b/112338294): Remove those once BufferHub moved to use Binder
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wdouble-promotion"
-#pragma clang diagnostic ignored "-Wgnu-case-range"
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#pragma clang diagnostic ignored "-Wpacked"
-#pragma clang diagnostic ignored "-Wshadow"
-#pragma clang diagnostic ignored "-Wsign-conversion"
-#pragma clang diagnostic ignored "-Wswitch-enum"
-#pragma clang diagnostic ignored "-Wundefined-func-template"
-#pragma clang diagnostic ignored "-Wunused-template"
-#pragma clang diagnostic ignored "-Wweak-vtables"
-#include <pdx/default_transport/client_channel.h>
-#include <pdx/default_transport/client_channel_factory.h>
-#include <pdx/file_handle.h>
-#include <private/dvr/bufferhub_rpc.h>
-#pragma clang diagnostic pop
-
 #include <poll.h>
 
 #include <android-base/unique_fd.h>
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+#include <log/log.h>
 #include <ui/BufferHubBuffer.h>
 #include <ui/BufferHubDefs.h>
+#include <utils/Trace.h>
 
-using android::base::unique_fd;
-using android::dvr::BufferTraits;
-using android::dvr::DetachedBufferRPC;
-using android::dvr::NativeHandleWrapper;
-
-// TODO(b/112338294): Remove PDX dependencies from libui.
-using android::pdx::LocalChannelHandle;
-using android::pdx::LocalHandle;
-using android::pdx::Status;
-using android::pdx::default_transport::ClientChannel;
-using android::pdx::default_transport::ClientChannelFactory;
+using ::android::base::unique_fd;
+using ::android::BufferHubDefs::AnyClientAcquired;
+using ::android::BufferHubDefs::AnyClientGained;
+using ::android::BufferHubDefs::IsClientAcquired;
+using ::android::BufferHubDefs::IsClientGained;
+using ::android::BufferHubDefs::IsClientPosted;
+using ::android::BufferHubDefs::IsClientReleased;
+using ::android::frameworks::bufferhub::V1_0::BufferHubStatus;
+using ::android::frameworks::bufferhub::V1_0::BufferTraits;
+using ::android::frameworks::bufferhub::V1_0::IBufferClient;
+using ::android::frameworks::bufferhub::V1_0::IBufferHub;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
 
 namespace android {
 
-namespace {
-
-// TODO(b/112338294): Remove this string literal after refactoring BufferHub
-// to use Binder.
-static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client";
-
-using BufferHubDefs::AnyClientAcquired;
-using BufferHubDefs::AnyClientGained;
-using BufferHubDefs::IsClientAcquired;
-using BufferHubDefs::IsClientGained;
-using BufferHubDefs::IsClientPosted;
-using BufferHubDefs::IsClientReleased;
-using BufferHubDefs::kHighBitsMask;
-
-} // namespace
-
-BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(kBufferHubClientPath)) {}
-
-BufferHubClient::BufferHubClient(LocalChannelHandle mChannelHandle)
-      : Client(ClientChannel::Create(std::move(mChannelHandle))) {}
-
-BufferHubClient::~BufferHubClient() {}
-
-bool BufferHubClient::IsValid() const {
-    return IsConnected() && GetChannelHandle().valid();
+std::unique_ptr<BufferHubBuffer> BufferHubBuffer::Create(uint32_t width, uint32_t height,
+                                                         uint32_t layerCount, uint32_t format,
+                                                         uint64_t usage, size_t userMetadataSize) {
+    auto buffer = std::unique_ptr<BufferHubBuffer>(
+            new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize));
+    return buffer->IsValid() ? std::move(buffer) : nullptr;
 }
 
-LocalChannelHandle BufferHubClient::TakeChannelHandle() {
-    if (IsConnected()) {
-        return std::move(GetChannelHandle());
-    } else {
-        return {};
+std::unique_ptr<BufferHubBuffer> BufferHubBuffer::Import(const native_handle_t* token) {
+    if (token == nullptr) {
+        ALOGE("%s: token cannot be nullptr!", __FUNCTION__);
+        return nullptr;
     }
+
+    auto buffer = std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(token));
+    return buffer->IsValid() ? std::move(buffer) : nullptr;
 }
 
 BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
-                                 uint32_t format, uint64_t usage, size_t mUserMetadataSize) {
+                                 uint32_t format, uint64_t usage, size_t userMetadataSize) {
     ATRACE_CALL();
-    ALOGD("%s: width=%u height=%u layerCount=%u, format=%u usage=%" PRIx64 " mUserMetadataSize=%zu",
-          __FUNCTION__, width, height, layerCount, format, usage, mUserMetadataSize);
+    ALOGD("%s: width=%u height=%u layerCount=%u, format=%u "
+          "usage=%" PRIx64 " mUserMetadataSize=%zu",
+          __FUNCTION__, width, height, layerCount, format, usage, userMetadataSize);
 
-    auto status =
-            mClient.InvokeRemoteMethod<DetachedBufferRPC::Create>(width, height, layerCount, format,
-                                                                  usage, mUserMetadataSize);
-    if (!status) {
-        ALOGE("%s: Failed to create detached buffer: %s", __FUNCTION__,
-              status.GetErrorMessage().c_str());
-        mClient.Close(-status.error());
+    sp<IBufferHub> bufferhub = IBufferHub::getService();
+    if (bufferhub.get() == nullptr) {
+        ALOGE("%s: BufferHub service not found!", __FUNCTION__);
+        return;
     }
 
-    const int ret = ImportGraphicBuffer();
-    if (ret < 0) {
-        ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret));
-        mClient.Close(ret);
+    AHardwareBuffer_Desc aDesc = {width, height,         layerCount,   format,
+                                  usage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+    HardwareBufferDescription desc;
+    memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
+
+    BufferHubStatus ret;
+    sp<IBufferClient> client;
+    BufferTraits bufferTraits;
+    IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& status, const auto& outClient,
+                                                 const auto& traits) {
+        ret = status;
+        client = std::move(outClient);
+        bufferTraits = std::move(traits);
+    };
+
+    if (!bufferhub->allocateBuffer(desc, static_cast<uint32_t>(userMetadataSize), alloc_cb)
+                 .isOk()) {
+        ALOGE("%s: allocateBuffer transaction failed!", __FUNCTION__);
+        return;
+    } else if (ret != BufferHubStatus::NO_ERROR) {
+        ALOGE("%s: allocateBuffer failed with error %u.", __FUNCTION__, ret);
+        return;
+    } else if (client == nullptr) {
+        ALOGE("%s: allocateBuffer got null BufferClient.", __FUNCTION__);
+        return;
+    }
+
+    const int importRet = initWithBufferTraits(bufferTraits);
+    if (importRet < 0) {
+        ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet));
+        client->close();
+    }
+    mBufferClient = std::move(client);
+}
+
+BufferHubBuffer::BufferHubBuffer(const native_handle_t* token) {
+    sp<IBufferHub> bufferhub = IBufferHub::getService();
+    if (bufferhub.get() == nullptr) {
+        ALOGE("%s: BufferHub service not found!", __FUNCTION__);
+        return;
+    }
+
+    BufferHubStatus ret;
+    sp<IBufferClient> client;
+    BufferTraits bufferTraits;
+    IBufferHub::importBuffer_cb import_cb = [&](const auto& status, const auto& outClient,
+                                                const auto& traits) {
+        ret = status;
+        client = std::move(outClient);
+        bufferTraits = std::move(traits);
+    };
+
+    // hidl_handle(native_handle_t*) simply creates a raw pointer reference withouth ownership
+    // transfer.
+    if (!bufferhub->importBuffer(hidl_handle(token), import_cb).isOk()) {
+        ALOGE("%s: importBuffer transaction failed!", __FUNCTION__);
+        return;
+    } else if (ret != BufferHubStatus::NO_ERROR) {
+        ALOGE("%s: importBuffer failed with error %u.", __FUNCTION__, ret);
+        return;
+    } else if (client == nullptr) {
+        ALOGE("%s: importBuffer got null BufferClient.", __FUNCTION__);
+        return;
+    }
+
+    const int importRet = initWithBufferTraits(bufferTraits);
+    if (importRet < 0) {
+        ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet));
+        client->close();
+    }
+    mBufferClient = std::move(client);
+}
+
+BufferHubBuffer::~BufferHubBuffer() {
+    // Close buffer client to avoid possible race condition: user could first duplicate and hold
+    // token with the original buffer gone, and then try to import the token. The close function
+    // will explicitly invalidate the token to avoid this.
+    if (mBufferClient != nullptr) {
+        if (!mBufferClient->close().isOk()) {
+            ALOGE("%s: close BufferClient transaction failed!", __FUNCTION__);
+        }
     }
 }
 
-BufferHubBuffer::BufferHubBuffer(LocalChannelHandle mChannelHandle)
-      : mClient(std::move(mChannelHandle)) {
-    const int ret = ImportGraphicBuffer();
-    if (ret < 0) {
-        ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret));
-        mClient.Close(ret);
-    }
-}
-
-int BufferHubBuffer::ImportGraphicBuffer() {
+int BufferHubBuffer::initWithBufferTraits(const BufferTraits& bufferTraits) {
     ATRACE_CALL();
 
-    auto status = mClient.InvokeRemoteMethod<DetachedBufferRPC::Import>();
-    if (!status) {
-        ALOGE("%s: Failed to import GraphicBuffer: %s", __FUNCTION__,
-              status.GetErrorMessage().c_str());
-        return -status.error();
+    if (bufferTraits.bufferInfo.getNativeHandle() == nullptr) {
+        ALOGE("%s: missing buffer info handle.", __FUNCTION__);
+        return -EINVAL;
     }
 
-    BufferTraits<LocalHandle> bufferTraits = status.take();
-    if (bufferTraits.id() < 0) {
-        ALOGE("%s: Received an invalid id!", __FUNCTION__);
-        return -EIO;
+    if (bufferTraits.bufferHandle.getNativeHandle() == nullptr) {
+        ALOGE("%s: missing gralloc handle.", __FUNCTION__);
+        return -EINVAL;
     }
 
-    // Stash the buffer id to replace the value in mId.
-    const int bufferId = bufferTraits.id();
+    int bufferId = bufferTraits.bufferInfo->data[1];
+    if (bufferId < 0) {
+        ALOGE("%s: Received an invalid (negative) id!", __FUNCTION__);
+        return -EINVAL;
+    }
 
-    // Import the metadata.
-    LocalHandle metadataHandle = bufferTraits.take_metadata_handle();
-    unique_fd metadataFd(metadataHandle.Release());
-    mMetadata = BufferHubMetadata::Import(std::move(metadataFd));
+    uint32_t clientBitMask;
+    memcpy(&clientBitMask, &bufferTraits.bufferInfo->data[2], sizeof(clientBitMask));
+    if (clientBitMask == 0U) {
+        ALOGE("%s: Received a invalid client state mask!", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    // Import the metadata. Dup since hidl_handle owns the fd
+    unique_fd ashmemFd(fcntl(bufferTraits.bufferInfo->data[0], F_DUPFD_CLOEXEC, 0));
+    mMetadata = BufferHubMetadata::Import(std::move(ashmemFd));
 
     if (!mMetadata.IsValid()) {
         ALOGE("%s: invalid metadata.", __FUNCTION__);
-        return -ENOMEM;
+        return -EINVAL;
     }
 
-    if (mMetadata.metadata_size() != bufferTraits.metadata_size()) {
-        ALOGE("%s: metadata buffer too small: %zu, expected: %" PRIu64 ".", __FUNCTION__,
-              mMetadata.metadata_size(), bufferTraits.metadata_size());
-        return -ENOMEM;
+    uint32_t userMetadataSize;
+    memcpy(&userMetadataSize, &bufferTraits.bufferInfo->data[3], sizeof(userMetadataSize));
+    if (mMetadata.user_metadata_size() != userMetadataSize) {
+        ALOGE("%s: user metadata size not match: expected %u, actual %zu.", __FUNCTION__,
+              userMetadataSize, mMetadata.user_metadata_size());
+        return -EINVAL;
     }
 
-    size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size());
+    size_t metadataSize = static_cast<size_t>(mMetadata.metadata_size());
     if (metadataSize < BufferHubDefs::kMetadataHeaderSize) {
         ALOGE("%s: metadata too small: %zu", __FUNCTION__, metadataSize);
         return -EINVAL;
@@ -178,24 +218,14 @@
 
     // Import the buffer: We only need to hold on the native_handle_t here so that
     // GraphicBuffer instance can be created in future.
-    mBufferHandle = bufferTraits.take_buffer_handle();
+    mBufferHandle = std::move(bufferTraits.bufferHandle);
+    memcpy(&mBufferDesc, &bufferTraits.bufferDesc, sizeof(AHardwareBuffer_Desc));
 
-    // Populate buffer desc based on buffer traits.
-    mBufferDesc.width = bufferTraits.width();
-    mBufferDesc.height = bufferTraits.height();
-    mBufferDesc.layers = bufferTraits.layer_count();
-    mBufferDesc.format = bufferTraits.format();
-    mBufferDesc.usage = bufferTraits.usage();
-    mBufferDesc.stride = bufferTraits.stride();
-    mBufferDesc.rfu0 = 0U;
-    mBufferDesc.rfu1 = 0U;
-
-    // If all imports succeed, replace the previous buffer and id.
     mId = bufferId;
-    mClientStateMask = bufferTraits.client_state_mask();
+    mClientStateMask = clientBitMask;
 
     // TODO(b/112012161) Set up shared fences.
-    ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, id(),
+    ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, mId,
           buffer_state_->load(std::memory_order_acquire));
     return 0;
 }
@@ -225,7 +255,7 @@
 
 int BufferHubBuffer::Post() {
     uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
-    uint32_t updated_buffer_state = (~mClientStateMask) & kHighBitsMask;
+    uint32_t updated_buffer_state = (~mClientStateMask) & BufferHubDefs::kHighBitsMask;
     do {
         if (!IsClientGained(current_buffer_state, mClientStateMask)) {
             ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d "
@@ -283,24 +313,37 @@
     return 0;
 }
 
-int BufferHubBuffer::Poll(int timeoutMs) {
-    ATRACE_CALL();
-
-    pollfd p = {mClient.event_fd(), POLLIN, 0};
-    return poll(&p, 1, timeoutMs);
+bool BufferHubBuffer::IsValid() const {
+    // TODO(b/68770788): check eventFd once implemented
+    return mBufferHandle.getNativeHandle() != nullptr && mId >= 0 && mClientStateMask != 0U &&
+            mMetadata.IsValid() && mBufferClient != nullptr;
 }
 
-Status<LocalChannelHandle> BufferHubBuffer::Duplicate() {
-    ATRACE_CALL();
-    ALOGD("%s: id=%d.", __FUNCTION__, mId);
-
-    auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
-
-    if (!statusOrHandle.ok()) {
-        ALOGE("%s: Failed to duplicate buffer (id=%d): %s.", __FUNCTION__, mId,
-              statusOrHandle.GetErrorMessage().c_str());
+native_handle_t* BufferHubBuffer::Duplicate() {
+    if (mBufferClient == nullptr) {
+        ALOGE("%s: missing BufferClient!", __FUNCTION__);
+        return nullptr;
     }
-    return statusOrHandle;
+
+    hidl_handle token;
+    BufferHubStatus ret;
+    IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) {
+        token = std::move(outToken);
+        ret = status;
+    };
+
+    if (!mBufferClient->duplicate(dup_cb).isOk()) {
+        ALOGE("%s: duplicate transaction failed!", __FUNCTION__);
+        return nullptr;
+    } else if (ret != BufferHubStatus::NO_ERROR) {
+        ALOGE("%s: duplicate failed with error %u.", __FUNCTION__, ret);
+        return nullptr;
+    } else if (token.getNativeHandle() == nullptr) {
+        ALOGE("%s: duplicate got null token.", __FUNCTION__);
+        return nullptr;
+    }
+
+    return native_handle_clone(token.getNativeHandle());
 }
 
 } // namespace android
diff --git a/libs/ui/OWNERS b/libs/ui/OWNERS
new file mode 100644
index 0000000..3938e4f
--- /dev/null
+++ b/libs/ui/OWNERS
@@ -0,0 +1,5 @@
+jiyong@google.com
+mathias@google.com
+olv@google.com
+romainguy@google.com
+stoza@google.com
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index 90dd391..c6a4a23 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -17,73 +17,43 @@
 #ifndef ANDROID_BUFFER_HUB_BUFFER_H_
 #define ANDROID_BUFFER_HUB_BUFFER_H_
 
-// We would eliminate the clang warnings introduced by libdpx.
-// TODO(b/112338294): Remove those once BufferHub moved to use Binder
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wdouble-promotion"
-#pragma clang diagnostic ignored "-Wgnu-case-range"
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#pragma clang diagnostic ignored "-Wpacked"
-#pragma clang diagnostic ignored "-Wshadow"
-#pragma clang diagnostic ignored "-Wsign-conversion"
-#pragma clang diagnostic ignored "-Wswitch-enum"
-#pragma clang diagnostic ignored "-Wundefined-func-template"
-#pragma clang diagnostic ignored "-Wunused-template"
-#pragma clang diagnostic ignored "-Wweak-vtables"
-#include <pdx/client.h>
-#include <private/dvr/native_handle_wrapper.h>
-#pragma clang diagnostic pop
-
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
 #include <android/hardware_buffer.h>
+#include <cutils/native_handle.h>
 #include <ui/BufferHubDefs.h>
 #include <ui/BufferHubMetadata.h>
 
 namespace android {
 
-class BufferHubClient : public pdx::Client {
-public:
-    BufferHubClient();
-    virtual ~BufferHubClient();
-    explicit BufferHubClient(pdx::LocalChannelHandle mChannelHandle);
-
-    bool IsValid() const;
-    pdx::LocalChannelHandle TakeChannelHandle();
-
-    using pdx::Client::Close;
-    using pdx::Client::event_fd;
-    using pdx::Client::GetChannel;
-    using pdx::Client::InvokeRemoteMethod;
-};
-
 class BufferHubBuffer {
 public:
-    // Allocates a standalone BufferHubBuffer not associated with any producer consumer set.
+    // Allocates a standalone BufferHubBuffer.
     static std::unique_ptr<BufferHubBuffer> Create(uint32_t width, uint32_t height,
                                                    uint32_t layerCount, uint32_t format,
-                                                   uint64_t usage, size_t userMetadataSize) {
-        return std::unique_ptr<BufferHubBuffer>(
-                new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize));
-    }
+                                                   uint64_t usage, size_t userMetadataSize);
 
-    // Imports the given channel handle to a BufferHubBuffer, taking ownership.
-    static std::unique_ptr<BufferHubBuffer> Import(pdx::LocalChannelHandle mChannelHandle) {
-        return std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(std::move(mChannelHandle)));
-    }
+    // Imports the given token to a BufferHubBuffer. Not taking ownership of the token. Caller
+    // should close and destroy the token after calling this function regardless of output.
+    // TODO(b/122543147): use a movable wrapper for token
+    static std::unique_ptr<BufferHubBuffer> Import(const native_handle_t* token);
 
     BufferHubBuffer(const BufferHubBuffer&) = delete;
     void operator=(const BufferHubBuffer&) = delete;
 
+    virtual ~BufferHubBuffer();
+
     // Gets ID of the buffer client. All BufferHubBuffer clients derived from the same buffer in
-    // bufferhubd share the same buffer id.
+    // BufferHub share the same buffer id.
     int id() const { return mId; }
 
-    // Returns the buffer description, which is guaranteed to be faithful values from bufferhubd.
+    // Returns the buffer description, which is guaranteed to be faithful values from BufferHub.
     const AHardwareBuffer_Desc& desc() const { return mBufferDesc; }
 
-    const native_handle_t* DuplicateHandle() { return mBufferHandle.DuplicateHandle(); }
+    // Duplicate the underlying Gralloc buffer handle. Caller is responsible to free the handle
+    // after use.
+    native_handle_t* DuplicateHandle() {
+        return native_handle_clone(mBufferHandle.getNativeHandle());
+    }
 
     // Returns the current value of MetadataHeader::buffer_state.
     uint32_t buffer_state() {
@@ -96,12 +66,12 @@
 
     size_t user_metadata_size() const { return mMetadata.user_metadata_size(); }
 
-    // Returns true if the buffer holds an open PDX channels towards bufferhubd.
-    bool IsConnected() const { return mClient.IsValid(); }
+    // Returns true if the BufferClient is still alive.
+    bool IsConnected() const { return mBufferClient->ping().isOk(); }
 
-    // Returns true if the buffer holds an valid native buffer handle that's availble for the client
-    // to read from and/or write into.
-    bool IsValid() const { return mBufferHandle.IsValid(); }
+    // Returns true if the buffer is valid: non-null buffer handle, valid id, valid client bit mask,
+    // valid metadata and valid buffer client
+    bool IsValid() const;
 
     // Gains the buffer for exclusive write permission. Read permission is implied once a buffer is
     // gained.
@@ -124,33 +94,24 @@
     // current cycle of the usage of the buffer.
     int Release();
 
-    // Returns the event mask for all the events that are pending on this buffer (see sys/poll.h for
-    // all possible bits).
-    pdx::Status<int> GetEventMask(int events) {
-        if (auto* channel = mClient.GetChannel()) {
-            return channel->GetEventMask(events);
-        } else {
-            return pdx::ErrorStatus(EINVAL);
-        }
-    }
-
-    // Polls the fd for |timeoutMs| milliseconds (-1 for infinity).
-    int Poll(int timeoutMs);
-
-    // Creates a BufferHubBuffer client from an existing one. The new client will
-    // share the same underlying gralloc buffer and ashmem region for metadata.
-    pdx::Status<pdx::LocalChannelHandle> Duplicate();
+    // Creates a token that stands for this BufferHubBuffer client and could be used for Import to
+    // create another BufferHubBuffer. The new BufferHubBuffer will share the same underlying
+    // gralloc buffer and ashmem region for metadata. Note that the caller owns the token and
+    // should free it after use.
+    // Returns a valid token on success, nullptr on failure.
+    // TODO(b/122543147): use a movable wrapper for token
+    native_handle_t* Duplicate();
 
 private:
     BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format,
                     uint64_t usage, size_t userMetadataSize);
 
-    BufferHubBuffer(pdx::LocalChannelHandle mChannelHandle);
+    BufferHubBuffer(const native_handle_t* token);
 
-    int ImportGraphicBuffer();
+    int initWithBufferTraits(const frameworks::bufferhub::V1_0::BufferTraits& bufferTraits);
 
     // Global id for the buffer that is consistent across processes.
-    int mId = -1;
+    int mId = 0;
 
     // Client state mask of this BufferHubBuffer object. It is unique amoung all
     // clients/users of the buffer.
@@ -159,8 +120,8 @@
     // Stores ground truth of the buffer.
     AHardwareBuffer_Desc mBufferDesc;
 
-    // Wrapps the gralloc buffer handle of this buffer.
-    dvr::NativeHandleWrapper<pdx::LocalHandle> mBufferHandle;
+    // Wraps the gralloc buffer handle of this buffer.
+    hardware::hidl_handle mBufferHandle;
 
     // An ashmem-based metadata object. The same shared memory are mapped to the
     // bufferhubd daemon and all buffer clients.
@@ -170,8 +131,8 @@
     std::atomic<uint32_t>* fence_state_ = nullptr;
     std::atomic<uint32_t>* active_clients_bit_mask_ = nullptr;
 
-    // PDX backend.
-    BufferHubClient mClient;
+    // HwBinder backend
+    sp<frameworks::bufferhub::V1_0::IBufferClient> mBufferClient;
 };
 
 } // namespace android
diff --git a/libs/ui/include/ui/BufferHubDefs.h b/libs/ui/include/ui/BufferHubDefs.h
index d259fef..069f0dc 100644
--- a/libs/ui/include/ui/BufferHubDefs.h
+++ b/libs/ui/include/ui/BufferHubDefs.h
@@ -158,6 +158,29 @@
 static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
 static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
 
+/**
+ * android.frameworks.bufferhub@1.0::BufferTraits.bufferInfo is an opaque handle. See
+ * https://cs.corp.google.com/android/frameworks/hardware/interfaces/bufferhub/1.0/types.hal for
+ * more details about android.frameworks.bufferhub@1.0::BufferTraits.
+ *
+ * This definition could be changed, but implementation of BufferHubService::buildBufferInfo
+ * (frameworks/native/services/bufferhub), VtsHalBufferHubV1_0TargetTest
+ * (frameworks/hardware/interfaces/bufferhub) and BufferHubBuffer::readBufferTraits (libui) will
+ * also need to be updated.
+ *
+ * It's definition should follow the following format:
+ * {
+ *   NumFds = 1,
+ *   NumInts = 3,
+ *   data[0] = Ashmem fd for BufferHubMetadata,
+ *   data[1] = buffer id,
+ *   data[2] = client state bit mask,
+ *   data[3] = user metadata size,
+ * }
+ */
+static constexpr int kBufferInfoNumFds = 1;
+static constexpr int kBufferInfoNumInts = 3;
+
 } // namespace BufferHubDefs
 
 } // namespace android
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index a670b3c..665469e 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -31,12 +31,14 @@
 cc_test {
     name: "GraphicBuffer_test",
     header_libs: [
-        "libbufferhub_headers",
         "libdvr_headers",
         "libnativewindow_headers",
     ],
     shared_libs: [
-        "libpdx_default_transport",
+        "android.frameworks.bufferhub@1.0",
+        "libcutils",
+        "libhidlbase",
+        "libhwbinder",
         "libui",
         "libutils",
     ],
@@ -47,7 +49,6 @@
 cc_test {
     name: "BufferHub_test",
     header_libs: [
-        "libbufferhub_headers",
         "libdvr_headers",
         "libnativewindow_headers",
     ],
@@ -60,7 +61,6 @@
         "libhidlbase",
         "libhwbinder",
         "liblog",
-        "libpdx_default_transport",
         "libui",
         "libutils"
     ],
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index 69b9590..cd744cd 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,10 +16,9 @@
 
 #define LOG_TAG "BufferHubBufferTest"
 
-#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
-#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
 #include <android/hardware_buffer.h>
 #include <cutils/native_handle.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <hidl/ServiceManagement.h>
 #include <hwbinder/IPCThreadState.h>
@@ -29,36 +28,38 @@
 
 namespace {
 
+using ::android::BufferHubDefs::AnyClientAcquired;
+using ::android::BufferHubDefs::AnyClientGained;
+using ::android::BufferHubDefs::AnyClientPosted;
+using ::android::BufferHubDefs::IsBufferReleased;
+using ::android::BufferHubDefs::IsClientAcquired;
+using ::android::BufferHubDefs::IsClientGained;
+using ::android::BufferHubDefs::IsClientPosted;
+using ::android::BufferHubDefs::IsClientReleased;
+using ::android::BufferHubDefs::kMetadataHeaderSize;
+using ::testing::IsNull;
+using ::testing::NotNull;
+
 const int kWidth = 640;
 const int kHeight = 480;
 const int kLayerCount = 1;
 const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
 const int kUsage = 0;
-const size_t kUserMetadataSize = 0;
-
-using BufferHubDefs::AnyClientAcquired;
-using BufferHubDefs::AnyClientGained;
-using BufferHubDefs::AnyClientPosted;
-using BufferHubDefs::IsBufferReleased;
-using BufferHubDefs::IsClientAcquired;
-using BufferHubDefs::IsClientGained;
-using BufferHubDefs::IsClientPosted;
-using BufferHubDefs::IsClientReleased;
-using BufferHubDefs::kFirstClientBitMask;
-using BufferHubDefs::kMetadataHeaderSize;
-using frameworks::bufferhub::V1_0::BufferHubStatus;
-using frameworks::bufferhub::V1_0::IBufferClient;
-using frameworks::bufferhub::V1_0::IBufferHub;
-using hardware::hidl_handle;
-using hardware::graphics::common::V1_2::HardwareBufferDescription;
-using hidl::base::V1_0::IBase;
-using pdx::LocalChannelHandle;
+const AHardwareBuffer_Desc kDesc = {kWidth, kHeight,        kLayerCount,  kFormat,
+                                    kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+const size_t kUserMetadataSize = 1;
 
 class BufferHubBufferTest : public ::testing::Test {
 protected:
     void SetUp() override { android::hardware::ProcessState::self()->startThreadPool(); }
 };
 
+bool cmpAHardwareBufferDesc(const AHardwareBuffer_Desc& desc, const AHardwareBuffer_Desc& other) {
+    // Not comparing stride because it's unknown before allocation
+    return desc.format == other.format && desc.height == other.height &&
+            desc.layers == other.layers && desc.usage == other.usage && desc.width == other.width;
+}
+
 class BufferHubBufferStateTransitionTest : public BufferHubBufferTest {
 protected:
     void SetUp() override {
@@ -78,91 +79,126 @@
 
 void BufferHubBufferStateTransitionTest::CreateTwoClientsOfABuffer() {
     b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
     b1ClientMask = b1->client_state_mask();
     ASSERT_NE(b1ClientMask, 0U);
-    auto statusOrHandle = b1->Duplicate();
-    ASSERT_TRUE(statusOrHandle);
-    LocalChannelHandle h2 = statusOrHandle.take();
-    b2 = BufferHubBuffer::Import(std::move(h2));
+
+    native_handle_t* token = b1->Duplicate();
+    ASSERT_THAT(token, NotNull());
+
+    // TODO(b/122543147): use a movalbe wrapper for token
+    b2 = BufferHubBuffer::Import(token);
+    native_handle_close(token);
+    native_handle_delete(token);
+    ASSERT_THAT(b2, NotNull());
+
     b2ClientMask = b2->client_state_mask();
     ASSERT_NE(b2ClientMask, 0U);
     ASSERT_NE(b2ClientMask, b1ClientMask);
 }
 
-TEST_F(BufferHubBufferTest, CreateBufferHubBufferFails) {
+TEST_F(BufferHubBufferTest, CreateBufferFails) {
     // Buffer Creation will fail: BLOB format requires height to be 1.
     auto b1 = BufferHubBuffer::Create(kWidth, /*height=*/2, kLayerCount,
                                       /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage, kUserMetadataSize);
 
-    EXPECT_FALSE(b1->IsConnected());
-    EXPECT_FALSE(b1->IsValid());
+    EXPECT_THAT(b1, IsNull());
 
     // Buffer Creation will fail: user metadata size too large.
     auto b2 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       /*userMetadataSize=*/std::numeric_limits<size_t>::max());
 
-    EXPECT_FALSE(b2->IsConnected());
-    EXPECT_FALSE(b2->IsValid());
+    EXPECT_THAT(b2, IsNull());
 
     // Buffer Creation will fail: user metadata size too large.
     const size_t userMetadataSize = std::numeric_limits<size_t>::max() - kMetadataHeaderSize;
     auto b3 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       userMetadataSize);
 
-    EXPECT_FALSE(b3->IsConnected());
-    EXPECT_FALSE(b3->IsValid());
+    EXPECT_THAT(b3, IsNull());
 }
 
-TEST_F(BufferHubBufferTest, CreateBufferHubBuffer) {
+TEST_F(BufferHubBufferTest, CreateBuffer) {
     auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
     EXPECT_TRUE(b1->IsConnected());
     EXPECT_TRUE(b1->IsValid());
-    EXPECT_NE(b1->id(), 0);
+    EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), kDesc));
+    EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
 }
 
-TEST_F(BufferHubBufferTest, DuplicateBufferHubBuffer) {
+TEST_F(BufferHubBufferTest, DuplicateAndImportBuffer) {
     auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       kUserMetadataSize);
-    int id1 = b1->id();
-    uint32_t bufferStateMask1 = b1->client_state_mask();
-    EXPECT_NE(bufferStateMask1, 0U);
+    ASSERT_THAT(b1, NotNull());
     EXPECT_TRUE(b1->IsValid());
-    EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
 
-    auto statusOrHandle = b1->Duplicate();
-    EXPECT_TRUE(statusOrHandle);
+    native_handle_t* token = b1->Duplicate();
+    EXPECT_TRUE(token);
 
     // The detached buffer should still be valid.
     EXPECT_TRUE(b1->IsConnected());
     EXPECT_TRUE(b1->IsValid());
 
-    // Gets the channel handle for the duplicated buffer.
-    LocalChannelHandle h2 = statusOrHandle.take();
-    EXPECT_TRUE(h2.valid());
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+    native_handle_close(token);
+    native_handle_delete(token);
 
-    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2));
-    EXPECT_FALSE(h2.valid());
-    ASSERT_TRUE(b2 != nullptr);
+    ASSERT_THAT(b2, NotNull());
     EXPECT_TRUE(b2->IsValid());
-    EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
 
-    int id2 = b2->id();
-    uint32_t bufferStateMask2 = b2->client_state_mask();
-    EXPECT_NE(bufferStateMask2, 0U);
+    EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), b2->desc()));
+    EXPECT_EQ(b1->user_metadata_size(), b2->user_metadata_size());
 
     // These two buffer instances are based on the same physical buffer under the
     // hood, so they should share the same id.
-    EXPECT_EQ(id1, id2);
+    EXPECT_EQ(b1->id(), b2->id());
     // We use client_state_mask() to tell those two instances apart.
-    EXPECT_NE(bufferStateMask1, bufferStateMask2);
+    EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
 
     // Both buffer instances should be in released state currently.
     EXPECT_TRUE(IsBufferReleased(b1->buffer_state()));
     EXPECT_TRUE(IsBufferReleased(b2->buffer_state()));
+}
 
-    // TODO(b/112338294): rewrite test after migration
-    return;
+TEST_F(BufferHubBufferTest, ImportFreedBuffer) {
+    auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+                                      kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
+    EXPECT_TRUE(b1->IsValid());
+
+    native_handle_t* token = b1->Duplicate();
+    EXPECT_TRUE(token);
+
+    // Explicitly destroy b1. Backend buffer should be freed and token becomes invalid
+    b1.reset();
+
+    // TODO(b/122543147): use a movalbe wrapper for token
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+    native_handle_close(token);
+    native_handle_delete(token);
+
+    // Import should fail with INVALID_TOKEN
+    EXPECT_THAT(b2, IsNull());
+}
+
+// nullptr must not crash the service
+TEST_F(BufferHubBufferTest, ImportNullToken) {
+    auto b1 = BufferHubBuffer::Import(nullptr);
+    EXPECT_THAT(b1, IsNull());
+}
+
+// TODO(b/118180214): remove the comment after ag/5856474 landed
+// This test has a very little chance to fail (number of existing tokens / 2 ^ 32)
+TEST_F(BufferHubBufferTest, ImportInvalidToken) {
+    native_handle_t* token = native_handle_create(/*numFds=*/0, /*numInts=*/1);
+    token->data[0] = 0;
+
+    auto b1 = BufferHubBuffer::Import(token);
+    native_handle_delete(token);
+
+    EXPECT_THAT(b1, IsNull());
 }
 
 TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromReleasedState) {
@@ -357,13 +393,20 @@
     std::unique_ptr<BufferHubBuffer> b1 =
             BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                     kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
     ASSERT_EQ(b1->Gain(), 0);
 
     // Create a consumer of the buffer and test if the consumer can acquire the
     // buffer if producer posts.
-    auto statusOrHandle = b1->Duplicate();
-    ASSERT_TRUE(statusOrHandle);
-    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(statusOrHandle.take()));
+    // TODO(b/122543147): use a movalbe wrapper for token
+    native_handle_t* token = b1->Duplicate();
+    ASSERT_TRUE(token);
+
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+    native_handle_close(token);
+    native_handle_delete(token);
+
+    ASSERT_THAT(b2, NotNull());
     ASSERT_NE(b1->client_state_mask(), b2->client_state_mask());
 
     ASSERT_EQ(b1->Post(), 0);
@@ -380,13 +423,20 @@
 
     // Create a consumer of the buffer and test if the consumer can acquire the
     // buffer if producer posts.
-    auto statusOrHandle = b1->Duplicate();
-    ASSERT_TRUE(statusOrHandle);
-    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(statusOrHandle.take()));
+    // TODO(b/122543147): use a movalbe wrapper for token
+    native_handle_t* token = b1->Duplicate();
+    ASSERT_TRUE(token);
+
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+    native_handle_close(token);
+    native_handle_delete(token);
+
+    ASSERT_THAT(b2, NotNull());
     ASSERT_NE(b1->client_state_mask(), b2->client_state_mask());
 
     EXPECT_EQ(b2->Acquire(), 0);
 }
 
 } // namespace
+
 } // namespace android
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index 81ab3ac..5b46454 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -39,7 +39,7 @@
     std::unique_ptr<BufferHubBuffer> b1 =
             BufferHubBuffer::Create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
                                     kTestUsage, /*userMetadataSize=*/0);
-    EXPECT_NE(b1, nullptr);
+    ASSERT_NE(b1, nullptr);
     EXPECT_TRUE(b1->IsValid());
 
     sp<GraphicBuffer> gb(new GraphicBuffer(std::move(b1)));
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 487a604..ed5a992 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -5,7 +5,6 @@
 #include <private/dvr/producer_buffer.h>
 #include <sys/epoll.h>
 #include <sys/eventfd.h>
-#include <ui/BufferHubBuffer.h>
 #include <ui/BufferHubDefs.h>
 
 #include <mutex>
@@ -20,9 +19,6 @@
     return result;                            \
   })()
 
-using android::BufferHubBuffer;
-using android::GraphicBuffer;
-using android::sp;
 using android::BufferHubDefs::AnyClientAcquired;
 using android::BufferHubDefs::AnyClientGained;
 using android::BufferHubDefs::AnyClientPosted;
@@ -31,19 +27,15 @@
 using android::BufferHubDefs::IsClientPosted;
 using android::BufferHubDefs::IsClientReleased;
 using android::BufferHubDefs::kFirstClientBitMask;
-using android::BufferHubDefs::kMetadataHeaderSize;
 using android::dvr::ConsumerBuffer;
 using android::dvr::ProducerBuffer;
-using android::pdx::LocalChannelHandle;
 using android::pdx::LocalHandle;
 using android::pdx::Status;
 
 const int kWidth = 640;
 const int kHeight = 480;
-const int kLayerCount = 1;
 const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
 const int kUsage = 0;
-const size_t kUserMetadataSize = 0;
 // Maximum number of consumers for the buffer that only has one producer in the
 // test.
 const size_t kMaxConsumerCount =
@@ -808,7 +800,7 @@
   // TODO(b/112338294) rewrite test after migration
   return;
 
-  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
+  /* std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   std::unique_ptr<ConsumerBuffer> c =
       ConsumerBuffer::Import(p->CreateConsumer());
@@ -876,49 +868,14 @@
   EXPECT_TRUE(d->IsConnected());
   EXPECT_TRUE(d->IsValid());
 
-  EXPECT_EQ(d->id(), p_id);
-}
-
-TEST_F(LibBufferHubTest, TestCreateBufferHubBufferFails) {
-  // Buffer Creation will fail: BLOB format requires height to be 1.
-  auto b1 = BufferHubBuffer::Create(kWidth, /*height=2*/ 2, kLayerCount,
-                                    /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage,
-                                    kUserMetadataSize);
-
-  EXPECT_FALSE(b1->IsConnected());
-  EXPECT_FALSE(b1->IsValid());
-
-  // Buffer Creation will fail: user metadata size too large.
-  auto b2 = BufferHubBuffer::Create(
-      kWidth, kHeight, kLayerCount, kFormat, kUsage,
-      /*user_metadata_size=*/std::numeric_limits<size_t>::max());
-
-  EXPECT_FALSE(b2->IsConnected());
-  EXPECT_FALSE(b2->IsValid());
-
-  // Buffer Creation will fail: user metadata size too large.
-  auto b3 = BufferHubBuffer::Create(
-      kWidth, kHeight, kLayerCount, kFormat, kUsage,
-      /*user_metadata_size=*/std::numeric_limits<size_t>::max() -
-          kMetadataHeaderSize);
-
-  EXPECT_FALSE(b3->IsConnected());
-  EXPECT_FALSE(b3->IsValid());
-}
-
-TEST_F(LibBufferHubTest, TestCreateBufferHubBuffer) {
-  auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
-                                    kUsage, kUserMetadataSize);
-  EXPECT_TRUE(b1->IsConnected());
-  EXPECT_TRUE(b1->IsValid());
-  EXPECT_NE(b1->id(), 0);
+  EXPECT_EQ(d->id(), p_id); */
 }
 
 TEST_F(LibBufferHubTest, TestDetach) {
   // TODO(b/112338294) rewrite test after migration
   return;
 
-  std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Create(
+  /* std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
   ASSERT_TRUE(p1.get() != nullptr);
   int p1_id = p1->id();
@@ -936,47 +893,5 @@
   EXPECT_FALSE(h1.valid());
   EXPECT_TRUE(b1->IsValid());
   int b1_id = b1->id();
-  EXPECT_EQ(b1_id, p1_id);
-}
-
-TEST_F(LibBufferHubTest, TestDuplicateBufferHubBuffer) {
-  auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
-                                    kUsage, kUserMetadataSize);
-  int b1_id = b1->id();
-  EXPECT_TRUE(b1->IsValid());
-  EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
-  EXPECT_NE(b1->client_state_mask(), 0U);
-
-  auto status_or_handle = b1->Duplicate();
-  EXPECT_TRUE(status_or_handle);
-
-  // The detached buffer should still be valid.
-  EXPECT_TRUE(b1->IsConnected());
-  EXPECT_TRUE(b1->IsValid());
-
-  // Gets the channel handle for the duplicated buffer.
-  LocalChannelHandle h2 = status_or_handle.take();
-  EXPECT_TRUE(h2.valid());
-
-  std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2));
-  EXPECT_FALSE(h2.valid());
-  ASSERT_TRUE(b2 != nullptr);
-  EXPECT_TRUE(b2->IsValid());
-  EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
-  EXPECT_NE(b2->client_state_mask(), 0U);
-
-  int b2_id = b2->id();
-
-  // These two buffer instances are based on the same physical buffer under the
-  // hood, so they should share the same id.
-  EXPECT_EQ(b1_id, b2_id);
-  // We use client_state_mask() to tell those two instances apart.
-  EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
-
-  // Both buffer instances should be in gained state.
-  EXPECT_TRUE(IsBufferReleased(b1->buffer_state()));
-  EXPECT_TRUE(IsBufferReleased(b2->buffer_state()));
-
-  // TODO(b/112338294) rewrite test after migration
-  return;
+  EXPECT_EQ(b1_id, p1_id); */
 }
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index f2c40fe..f5761d5 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -162,39 +162,6 @@
   void operator=(const BufferTraits&) = delete;
 };
 
-struct DetachedBufferRPC {
- private:
-  enum {
-    kOpDetachedBufferBase = 1000,
-
-    // Allocates a standalone DetachedBuffer not associated with any producer
-    // consumer set.
-    kOpCreate,
-
-    // Imports the given channel handle to a DetachedBuffer, taking ownership.
-    kOpImport,
-
-    // Creates a DetachedBuffer client from an existing one. The new client will
-    // share the same underlying gralloc buffer and ashmem region for metadata.
-    kOpDuplicate,
-  };
-
-  // Aliases.
-  using LocalChannelHandle = pdx::LocalChannelHandle;
-  using LocalHandle = pdx::LocalHandle;
-  using Void = pdx::rpc::Void;
-
- public:
-  PDX_REMOTE_METHOD(Create, kOpCreate,
-                    void(uint32_t width, uint32_t height, uint32_t layer_count,
-                         uint32_t format, uint64_t usage,
-                         size_t user_metadata_size));
-  PDX_REMOTE_METHOD(Import, kOpImport, BufferTraits<LocalHandle>(Void));
-  PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));
-
-  PDX_REMOTE_API(API, Create, Import, Duplicate);
-};
-
 }  // namespace dvr
 }  // namespace android
 
diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp
index dd8fbfc..f936ac0 100644
--- a/opengl/libs/EGL/egl_layers.cpp
+++ b/opengl/libs/EGL/egl_layers.cpp
@@ -375,12 +375,13 @@
                 auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
                 if (app_namespace && !android::base::StartsWith(layer, kSystemLayerLibraryDir)) {
                     bool native_bridge = false;
-                    std::string error_message;
-                    handle = OpenNativeLibrary(app_namespace, layer.c_str(), &native_bridge,
-                                               &error_message);
+                    char* error_message = nullptr;
+                    handle = OpenNativeLibraryInNamespace(
+                        app_namespace, layer.c_str(), &native_bridge, &error_message);
                     if (!handle) {
                         ALOGE("Failed to load layer %s with error: %s", layer.c_str(),
-                              error_message.c_str());
+                              error_message);
+                        android::NativeLoaderFreeErrorMessage(error_message);
                         return;
                     }
 
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
index 72d210c..a4b81fe 100644
--- a/services/bufferhub/Android.bp
+++ b/services/bufferhub/Android.bp
@@ -34,6 +34,7 @@
     ],
     shared_libs: [
         "android.frameworks.bufferhub@1.0",
+        "libcrypto",
         "libcutils",
         "libhidlbase",
         "libhidltransport",
@@ -60,6 +61,7 @@
     shared_libs: [
         "android.frameworks.bufferhub@1.0",
         "libbufferhubservice",
+        "libcrypto",
         "libcutils",
         "libhidltransport",
         "libhwbinder",
diff --git a/services/bufferhub/BufferHubIdGenerator.cpp b/services/bufferhub/BufferHubIdGenerator.cpp
index 6444a03..2c12f0e 100644
--- a/services/bufferhub/BufferHubIdGenerator.cpp
+++ b/services/bufferhub/BufferHubIdGenerator.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <bufferhub/BufferHubIdGenerator.h>
+#include <log/log.h>
 
 namespace android {
 namespace frameworks {
@@ -22,20 +23,18 @@
 namespace V1_0 {
 namespace implementation {
 
-constexpr uint32_t BufferHubIdGenerator::kInvalidId;
-
 BufferHubIdGenerator& BufferHubIdGenerator::getInstance() {
     static BufferHubIdGenerator generator;
 
     return generator;
 }
 
-uint32_t BufferHubIdGenerator::getId() {
+int BufferHubIdGenerator::getId() {
     std::lock_guard<std::mutex> lock(mIdsInUseMutex);
 
     do {
-        if (++mLastId >= std::numeric_limits<uint32_t>::max()) {
-            mLastId = kInvalidId + 1;
+        if (++mLastId >= std::numeric_limits<int>::max()) {
+            mLastId = 0;
         }
     } while (mIdsInUse.find(mLastId) != mIdsInUse.end());
 
@@ -43,15 +42,14 @@
     return mLastId;
 }
 
-bool BufferHubIdGenerator::freeId(uint32_t id) {
+void BufferHubIdGenerator::freeId(int id) {
     std::lock_guard<std::mutex> lock(mIdsInUseMutex);
     auto iter = mIdsInUse.find(id);
     if (iter != mIdsInUse.end()) {
         mIdsInUse.erase(iter);
-        return true;
+    } else {
+        ALOGW("%s: Cannot free nonexistent id #%d", __FUNCTION__, id);
     }
-
-    return false;
 }
 
 } // namespace implementation
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index 54796a2..a40443d 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -14,14 +14,18 @@
  * limitations under the License.
  */
 
+#include <array>
 #include <iomanip>
+#include <random>
 #include <sstream>
 
 #include <android/hardware_buffer.h>
 #include <bufferhub/BufferHubService.h>
 #include <cutils/native_handle.h>
 #include <log/log.h>
+#include <openssl/hmac.h>
 #include <system/graphics-base.h>
+#include <ui/BufferHubDefs.h>
 
 using ::android::BufferHubDefs::MetadataHeader;
 using ::android::hardware::Void;
@@ -32,6 +36,13 @@
 namespace V1_0 {
 namespace implementation {
 
+BufferHubService::BufferHubService() {
+    std::mt19937_64 randomEngine;
+    randomEngine.seed(time(nullptr));
+
+    mKey = randomEngine();
+}
+
 Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& description,
                                               const uint32_t userMetadataSize,
                                               allocateBuffer_cb _hidl_cb) {
@@ -54,10 +65,12 @@
     std::lock_guard<std::mutex> lock(mClientSetMutex);
     mClientSet.emplace(client);
 
+    hidl_handle bufferInfo =
+            buildBufferInfo(node->id(), node->AddNewActiveClientsBitToMask(),
+                            node->user_metadata_size(), node->metadata().ashmem_fd());
     BufferTraits bufferTraits = {/*bufferDesc=*/description,
                                  /*bufferHandle=*/hidl_handle(node->buffer_handle()),
-                                 // TODO(b/116681016): return real data to client
-                                 /*bufferInfo=*/hidl_handle()};
+                                 /*bufferInfo=*/bufferInfo};
 
     _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
              /*bufferTraits=*/bufferTraits);
@@ -66,27 +79,49 @@
 
 Return<void> BufferHubService::importBuffer(const hidl_handle& tokenHandle,
                                             importBuffer_cb _hidl_cb) {
-    if (!tokenHandle.getNativeHandle() || tokenHandle->numFds != 0 || tokenHandle->numInts != 1) {
+    if (!tokenHandle.getNativeHandle() || tokenHandle->numFds != 0 || tokenHandle->numInts <= 1) {
         // nullptr handle or wrong format
         _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
                  /*bufferTraits=*/{});
         return Void();
     }
 
-    uint32_t token = tokenHandle->data[0];
+    int tokenId = tokenHandle->data[0];
 
     wp<BufferClient> originClientWp;
     {
-        std::lock_guard<std::mutex> lock(mTokenMapMutex);
-        auto iter = mTokenMap.find(token);
+        std::lock_guard<std::mutex> lock(mTokenMutex);
+        auto iter = mTokenMap.find(tokenId);
         if (iter == mTokenMap.end()) {
-            // Invalid token
+            // Token Id not exist
+            ALOGD("%s: token #%d not found.", __FUNCTION__, tokenId);
             _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
                      /*bufferTraits=*/{});
             return Void();
         }
 
-        originClientWp = iter->second;
+        const std::vector<uint8_t>& tokenHMAC = iter->second.first;
+
+        int numIntsForHMAC = (int)ceil(tokenHMAC.size() * sizeof(uint8_t) / (double)sizeof(int));
+        if (tokenHandle->numInts - 1 != numIntsForHMAC) {
+            // HMAC size not match
+            ALOGD("%s: token #%d HMAC size not match. Expected: %d Actual: %d", __FUNCTION__,
+                  tokenId, numIntsForHMAC, tokenHandle->numInts - 1);
+            _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
+                     /*bufferTraits=*/{});
+            return Void();
+        }
+
+        size_t hmacSize = tokenHMAC.size() * sizeof(uint8_t);
+        if (memcmp(tokenHMAC.data(), &tokenHandle->data[1], hmacSize) != 0) {
+            // HMAC not match
+            ALOGD("%s: token #%d HMAC not match.", __FUNCTION__, tokenId);
+            _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
+                     /*bufferTraits=*/{});
+            return Void();
+        }
+
+        originClientWp = iter->second.second;
         mTokenMap.erase(iter);
     }
 
@@ -119,10 +154,12 @@
     HardwareBufferDescription bufferDesc;
     memcpy(&bufferDesc, &node->buffer_desc(), sizeof(HardwareBufferDescription));
 
+    hidl_handle bufferInfo =
+            buildBufferInfo(node->id(), clientStateMask, node->user_metadata_size(),
+                            node->metadata().ashmem_fd());
     BufferTraits bufferTraits = {/*bufferDesc=*/bufferDesc,
                                  /*bufferHandle=*/hidl_handle(node->buffer_handle()),
-                                 // TODO(b/116681016): return real data to client
-                                 /*bufferInfo=*/hidl_handle()};
+                                 /*bufferInfo=*/bufferInfo};
 
     _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
              /*bufferTraits=*/bufferTraits);
@@ -179,7 +216,7 @@
     stream << " ";
     stream << std::setw(10) << "State";
     stream << " ";
-    stream << std::setw(10) << "Index";
+    stream << std::setw(8) << "Index";
     stream << std::endl;
 
     for (auto iter = clientCount.begin(); iter != clientCount.end(); ++iter) {
@@ -214,6 +251,7 @@
         stream << " ";
         stream << "0x" << std::hex << std::setfill('0');
         stream << std::setw(8) << /*State=*/state;
+        stream << std::dec << std::setfill(' ');
         stream << " ";
         stream << std::setw(8) << /*Index=*/index;
         stream << std::endl;
@@ -225,9 +263,9 @@
     // Map from bufferId to tokenCount
     std::map<int, uint32_t> tokenCount;
     {
-        std::lock_guard<std::mutex> lock(mTokenMapMutex);
+        std::lock_guard<std::mutex> lock(mTokenMutex);
         for (auto iter = mTokenMap.begin(); iter != mTokenMap.end(); ++iter) {
-            sp<BufferClient> client = iter->second.promote();
+            sp<BufferClient> client = iter->second.second.promote();
             if (client != nullptr) {
                 const std::shared_ptr<BufferNode> node = client->getBufferNode();
                 auto mapIter = tokenCount.find(node->id());
@@ -262,21 +300,35 @@
 }
 
 hidl_handle BufferHubService::registerToken(const wp<BufferClient>& client) {
-    uint32_t token;
-    std::lock_guard<std::mutex> lock(mTokenMapMutex);
+    // Find next available token id
+    std::lock_guard<std::mutex> lock(mTokenMutex);
     do {
-        token = mTokenEngine();
-    } while (mTokenMap.find(token) != mTokenMap.end());
+        ++mLastTokenId;
+    } while (mTokenMap.find(mLastTokenId) != mTokenMap.end());
 
-    // native_handle_t use int[], so here need one slots to fit in uint32_t
-    native_handle_t* handle = native_handle_create(/*numFds=*/0, /*numInts=*/1);
-    handle->data[0] = token;
+    std::array<uint8_t, EVP_MAX_MD_SIZE> hmac;
+    uint32_t hmacSize = 0U;
+
+    HMAC(/*evp_md=*/EVP_sha256(), /*key=*/&mKey, /*key_len=*/kKeyLen,
+         /*data=*/(uint8_t*)&mLastTokenId, /*data_len=*/mTokenIdSize,
+         /*out=*/hmac.data(), /*out_len=*/&hmacSize);
+
+    int numIntsForHMAC = (int)ceil(hmacSize / (double)sizeof(int));
+    native_handle_t* handle = native_handle_create(/*numFds=*/0, /*numInts=*/1 + numIntsForHMAC);
+    handle->data[0] = mLastTokenId;
+    // Set all the the bits of last int to 0 since it might not be fully overwritten
+    handle->data[numIntsForHMAC] = 0;
+    memcpy(&handle->data[1], hmac.data(), hmacSize);
 
     // returnToken owns the native_handle_t* thus doing lifecycle management
     hidl_handle returnToken;
     returnToken.setTo(handle, /*shoudOwn=*/true);
 
-    mTokenMap.emplace(token, client);
+    std::vector<uint8_t> hmacVec;
+    hmacVec.resize(hmacSize);
+    memcpy(hmacVec.data(), hmac.data(), hmacSize);
+    mTokenMap.emplace(mLastTokenId, std::pair(hmacVec, client));
+
     return returnToken;
 }
 
@@ -290,11 +342,31 @@
     }
 }
 
+// Implementation of this function should be consistent with the definition of bufferInfo handle in
+// ui/BufferHubDefs.h.
+hidl_handle BufferHubService::buildBufferInfo(int bufferId, uint32_t clientBitMask,
+                                              uint32_t userMetadataSize, const int metadataFd) {
+    native_handle_t* infoHandle = native_handle_create(BufferHubDefs::kBufferInfoNumFds,
+                                                       BufferHubDefs::kBufferInfoNumInts);
+
+    infoHandle->data[0] = dup(metadataFd);
+    infoHandle->data[1] = bufferId;
+    // Use memcpy to convert to int without missing digit.
+    // TOOD(b/121345852): use bit_cast to unpack bufferInfo when C++20 becomes available.
+    memcpy(&infoHandle->data[2], &clientBitMask, sizeof(clientBitMask));
+    memcpy(&infoHandle->data[3], &userMetadataSize, sizeof(userMetadataSize));
+
+    hidl_handle bufferInfo;
+    bufferInfo.setTo(infoHandle, /*shouldOwn=*/true);
+
+    return bufferInfo;
+}
+
 void BufferHubService::removeTokenByClient(const BufferClient* client) {
-    std::lock_guard<std::mutex> lock(mTokenMapMutex);
+    std::lock_guard<std::mutex> lock(mTokenMutex);
     auto iter = mTokenMap.begin();
     while (iter != mTokenMap.end()) {
-        if (iter->second == client) {
+        if (iter->second.second == client) {
             auto oldIter = iter;
             ++iter;
             mTokenMap.erase(oldIter);
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index da19a6f..5106390 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -30,7 +30,7 @@
 
 // Allocates a new BufferNode.
 BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
-                       uint64_t usage, size_t user_metadata_size, uint32_t id)
+                       uint64_t usage, size_t user_metadata_size, int id)
       : mId(id) {
     uint32_t out_stride = 0;
     // graphicBufferId is not used in GraphicBufferAllocator::allocate
@@ -73,12 +73,8 @@
     }
 
     // Free the id, if valid
-    if (id() != BufferHubIdGenerator::kInvalidId) {
-        if (BufferHubIdGenerator::getInstance().freeId(id())) {
-            ALOGI("%s: id #%u is freed.", __FUNCTION__, id());
-        } else {
-            ALOGE("%s: Cannot free nonexistent id #%u", __FUNCTION__, id());
-        }
+    if (mId >= 0) {
+        BufferHubIdGenerator::getInstance().freeId(mId);
     }
 }
 
diff --git a/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
index b51fcda..ef7c077 100644
--- a/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
+++ b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
@@ -28,30 +28,28 @@
 namespace V1_0 {
 namespace implementation {
 
-// A thread-safe incremental uint32_t id generator.
+// A thread-safe, non-negative, incremental, int id generator.
 class BufferHubIdGenerator {
 public:
-    // 0 is considered invalid
-    static constexpr uint32_t kInvalidId = 0U;
-
     // Get the singleton instance of this class
     static BufferHubIdGenerator& getInstance();
 
-    // Gets next available id. If next id is greater than std::numeric_limits<uint32_t>::max() (2 ^
-    // 32 - 1), it will try to get an id start from 1 again.
-    uint32_t getId();
+    // Gets next available id. If next id is greater than std::numeric_limits<int32_t>::max(), it
+    // will try to get an id start from 0 again.
+    int getId();
 
-    // Free a specific id. Return true on freed, false on not found.
-    bool freeId(uint32_t id);
+    // Free a specific id.
+    void freeId(int id);
 
 private:
     BufferHubIdGenerator() = default;
     ~BufferHubIdGenerator() = default;
 
+    // Start from -1 so all valid ids will be >= 0
+    int mLastId = -1;
+
     std::mutex mIdsInUseMutex;
-    // Start from kInvalidID to avoid generating it.
-    uint32_t mLastId = kInvalidId;
-    std::set<uint32_t> mIdsInUse GUARDED_BY(mIdsInUseMutex);
+    std::set<int> mIdsInUse GUARDED_BY(mIdsInUseMutex);
 };
 
 } // namespace implementation
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
index 255f329..23e664e 100644
--- a/services/bufferhub/include/bufferhub/BufferHubService.h
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -17,8 +17,10 @@
 #ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
 #define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
 
+#include <map>
 #include <mutex>
-#include <random>
+#include <set>
+#include <vector>
 
 #include <android/frameworks/bufferhub/1.0/IBufferHub.h>
 #include <bufferhub/BufferClient.h>
@@ -39,6 +41,8 @@
 
 class BufferHubService : public IBufferHub {
 public:
+    BufferHubService();
+
     Return<void> allocateBuffer(const HardwareBufferDescription& description,
                                 const uint32_t userMetadataSize,
                                 allocateBuffer_cb _hidl_cb) override;
@@ -53,6 +57,10 @@
     void onClientClosed(const BufferClient* client);
 
 private:
+    // Helper function to build BufferTraits.bufferInfo handle
+    hidl_handle buildBufferInfo(int bufferId, uint32_t clientBitMask, uint32_t userMetadataSize,
+                                const int metadataFd);
+
     // Helper function to remove all the token belongs to a specific client.
     void removeTokenByClient(const BufferClient* client);
 
@@ -60,11 +68,19 @@
     std::mutex mClientSetMutex;
     std::set<wp<BufferClient>> mClientSet GUARDED_BY(mClientSetMutex);
 
-    // TODO(b/118180214): use a more secure implementation
-    std::mt19937 mTokenEngine;
-    // The mapping from token to the client creates it.
-    std::mutex mTokenMapMutex;
-    std::map<uint32_t, const wp<BufferClient>> mTokenMap GUARDED_BY(mTokenMapMutex);
+    // Token generation related
+    // A random number used as private key for HMAC
+    uint64_t mKey;
+    static constexpr size_t kKeyLen = sizeof(uint64_t);
+
+    std::mutex mTokenMutex;
+    // The first TokenId will be 1. TokenId could be negative.
+    int mLastTokenId GUARDED_BY(mTokenMutex) = 0;
+    static constexpr size_t mTokenIdSize = sizeof(int);
+    // A map from token id to the token-buffer_client pair. Using token id as the key to reduce
+    // looking up time
+    std::map<int, std::pair<std::vector<uint8_t>, const wp<BufferClient>>> mTokenMap
+            GUARDED_BY(mTokenMutex);
 };
 
 } // namespace implementation
diff --git a/services/bufferhub/include/bufferhub/BufferNode.h b/services/bufferhub/include/bufferhub/BufferNode.h
index cf56c33..b7a195b 100644
--- a/services/bufferhub/include/bufferhub/BufferNode.h
+++ b/services/bufferhub/include/bufferhub/BufferNode.h
@@ -16,15 +16,14 @@
 public:
     // Allocates a new BufferNode.
     BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
-               uint64_t usage, size_t user_metadata_size,
-               uint32_t id = BufferHubIdGenerator::kInvalidId);
+               uint64_t usage, size_t user_metadata_size, int id = -1);
 
     ~BufferNode();
 
     // Returns whether the object holds a valid metadata.
     bool IsValid() const { return metadata_.IsValid(); }
 
-    uint32_t id() const { return mId; }
+    int id() const { return mId; }
 
     size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
 
@@ -64,10 +63,10 @@
     // Metadata in shared memory.
     BufferHubMetadata metadata_;
 
-    // A system-unique id generated by bufferhub from 1 to std::numeric_limits<uint32_t>::max().
-    // BufferNodes not created by bufferhub will have id = 0, meaning "not specified".
-    // TODO(b/118891412): remove default id = 0 and update comments after pdx is no longer in use
-    const uint32_t mId = 0;
+    // A system-unique id generated by bufferhub from 0 to std::numeric_limits<int>::max().
+    // BufferNodes not created by bufferhub will have id < 0, meaning "not specified".
+    // TODO(b/118891412): remove default id = -1 and update comments after pdx is no longer in use
+    const int mId = -1;
 
     // The following variables are atomic variables in metadata_ that are visible
     // to Bn object and Bp objects. Please find more info in
diff --git a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
index fe01013..fb6de0d 100644
--- a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
+++ b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
@@ -15,25 +15,28 @@
 };
 
 TEST_F(BufferHubIdGeneratorTest, TestGenerateAndFreeID) {
-    uint32_t id = mIdGenerator->getId();
-    EXPECT_NE(id, BufferHubIdGenerator::kInvalidId);
+    int id = mIdGenerator->getId();
+    EXPECT_GE(id, 0);
 
-    EXPECT_TRUE(mIdGenerator->freeId(id));
-    EXPECT_FALSE(mIdGenerator->freeId(id));
+    mIdGenerator->freeId(id);
 }
 
 TEST_F(BufferHubIdGeneratorTest, TestGenerateUniqueIncrementalID) {
     // 10 IDs should not overflow the UniqueIdGenerator to cause a roll back to start, so the
     // resulting IDs should still keep incresing.
-    const size_t kTestSize = 10U;
-    uint32_t ids[kTestSize];
-    for (size_t i = 0UL; i < kTestSize; ++i) {
+    const int kTestSize = 10;
+    int ids[kTestSize];
+    for (int i = 0; i < kTestSize; ++i) {
         ids[i] = mIdGenerator->getId();
-        EXPECT_NE(ids[i], BufferHubIdGenerator::kInvalidId);
+        EXPECT_GE(ids[i], 0);
         if (i >= 1) {
             EXPECT_GT(ids[i], ids[i - 1]);
         }
     }
+
+    for (int i = 0; i < kTestSize; ++i) {
+        mIdGenerator->freeId(ids[i]);
+    }
 }
 
 } // namespace
diff --git a/services/displayservice/OWNERS b/services/displayservice/OWNERS
new file mode 100644
index 0000000..7a3e4c2
--- /dev/null
+++ b/services/displayservice/OWNERS
@@ -0,0 +1,2 @@
+smoreland@google.com
+lpy@google.com
diff --git a/services/displayservice/include/displayservice/DisplayEventReceiver.h b/services/displayservice/include/displayservice/DisplayEventReceiver.h
index 5d569b6..042a054 100644
--- a/services/displayservice/include/displayservice/DisplayEventReceiver.h
+++ b/services/displayservice/include/displayservice/DisplayEventReceiver.h
@@ -45,7 +45,7 @@
     using FwkReceiver = ::android::DisplayEventReceiver;
 
     struct AttachedEvent : LooperCallback {
-        AttachedEvent(const sp<IEventCallback> &callback);
+        explicit AttachedEvent(const sp<IEventCallback> &callback);
         ~AttachedEvent();
 
         bool detach();
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 18c3ded..cf9d3c7 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -40,6 +40,7 @@
 #include <hardware_legacy/power.h>
 
 #include <android-base/stringprintf.h>
+#include <cutils/properties.h>
 #include <openssl/sha.h>
 #include <utils/Log.h>
 #include <utils/Timers.h>
@@ -108,6 +109,19 @@
     return strstr(name, "v4l-touch") == name;
 }
 
+/**
+ * Returns true if V4L devices should be scanned.
+ *
+ * The system property ro.input.video_enabled can be used to control whether
+ * EventHub scans and opens V4L devices. As V4L does not support multiple
+ * clients, EventHub effectively blocks access to these devices when it opens
+ * them. This property enables other clients to read these devices for testing
+ * and development.
+ */
+static bool isV4lScanningEnabled() {
+  return property_get_bool("ro.input.video_enabled", true /* default_value */);
+}
+
 static nsecs_t processEventTimestamp(const struct input_event& event) {
     // Use the time specified in the event instead of the current time
     // so that downstream code can get more accurate estimates of
@@ -237,9 +251,14 @@
     mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
     LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s",
             DEVICE_PATH, strerror(errno));
-    mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
-    LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
-            VIDEO_DEVICE_PATH, strerror(errno));
+    if (isV4lScanningEnabled()) {
+        mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
+        LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
+                VIDEO_DEVICE_PATH, strerror(errno));
+    } else {
+        mVideoWd = -1;
+        ALOGI("Video device scanning disabled");
+    }
 
     struct epoll_event eventItem;
     memset(&eventItem, 0, sizeof(eventItem));
@@ -1056,9 +1075,11 @@
     if(result < 0) {
         ALOGE("scan dir failed for %s", DEVICE_PATH);
     }
-    result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
-    if (result != OK) {
-        ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
+    if (isV4lScanningEnabled()) {
+        result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
+        if (result != OK) {
+            ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
+        }
     }
     if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
         createVirtualKeyboardLocked();
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 7997928..9af189a 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2691,7 +2691,7 @@
             event.initialize(args->deviceId, args->source, args->displayId,
                     args->action, args->actionButton,
                     args->flags, args->edgeFlags, args->metaState, args->buttonState,
-                    0, 0, args->xPrecision, args->yPrecision,
+                    args->classification, 0, 0, args->xPrecision, args->yPrecision,
                     args->downTime, args->eventTime,
                     args->pointerCount, args->pointerProperties, args->pointerCoords);
 
@@ -3131,7 +3131,9 @@
 
             for (size_t i = 0; i < newHandles.size(); i++) {
                 const sp<InputWindowHandle>& windowHandle = newHandles.itemAt(i);
-                if (windowHandle->getInfo()->hasFocus && windowHandle->getInfo()->visible) {
+                // Set newFocusedWindowHandle to the top most focused window instead of the last one
+                if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus
+                        && windowHandle->getInfo()->visible) {
                     newFocusedWindowHandle = windowHandle;
                 }
                 if (windowHandle == mLastHoverWindowHandle) {
@@ -3175,7 +3177,7 @@
             }
 
             if (mFocusedDisplayId == displayId) {
-                onFocusChangedLocked(newFocusedWindowHandle);
+                onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle);
             }
 
         }
@@ -3293,7 +3295,7 @@
             // Sanity check
             sp<InputWindowHandle> newFocusedWindowHandle =
                     getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
-            onFocusChangedLocked(newFocusedWindowHandle);
+            onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle);
 
             if (newFocusedWindowHandle == nullptr) {
                 ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
@@ -3374,11 +3376,6 @@
     mLooper->wake();
 }
 
-bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
-        const sp<InputChannel>& toChannel) {
-    return transferTouchFocus(fromChannel->getToken(), toChannel->getToken());
-}
-
 bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
     if (fromToken == toToken) {
 #if DEBUG_FOCUS
@@ -3392,14 +3389,14 @@
 
         sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromToken);
         sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toToken);
-#if DEBUG_FOCUS
-        ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s",
-            fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str());
-#endif
         if (fromWindowHandle == nullptr || toWindowHandle == nullptr) {
             ALOGW("Cannot transfer focus because from or to window not found.");
             return false;
         }
+#if DEBUG_FOCUS
+        ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s",
+            fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str());
+#endif
         if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) {
 #if DEBUG_FOCUS
             ALOGD("Cannot transfer focus because windows are on different displays.");
@@ -3860,11 +3857,14 @@
     commandEntry->connection = connection;
 }
 
-void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& newFocus) {
-    sp<IBinder> token = newFocus != nullptr ? newFocus->getToken() : nullptr;
+void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
+        const sp<InputWindowHandle>& newFocus) {
+    sp<IBinder> oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr;
+    sp<IBinder> newToken = newFocus != nullptr ? newFocus->getToken() : nullptr;
     CommandEntry* commandEntry = postCommandLocked(
             & InputDispatcher::doNotifyFocusChangedLockedInterruptible);
-    commandEntry->token = token;
+    commandEntry->oldToken = oldToken;
+    commandEntry->newToken = newToken;
 }
 
 void InputDispatcher::onANRLocked(
@@ -3926,9 +3926,10 @@
 
 void InputDispatcher::doNotifyFocusChangedLockedInterruptible(
         CommandEntry* commandEntry) {
-    sp<IBinder> token = commandEntry->token;
+    sp<IBinder> oldToken = commandEntry->oldToken;
+    sp<IBinder> newToken = commandEntry->newToken;
     mLock.unlock();
-    mPolicy->notifyFocusChanged(token);
+    mPolicy->notifyFocusChanged(oldToken, newToken);
     mLock.lock();
 }
 
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 970632e..49de6f3 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -37,7 +37,7 @@
 #include <unordered_map>
 
 #include "InputListener.h"
-#include "InputReporter.h"
+#include "InputReporterInterface.h"
 
 
 namespace android {
@@ -217,7 +217,7 @@
 
     /* Notifies the system that an input channel is unrecoverably broken. */
     virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
-    virtual void notifyFocusChanged(const sp<IBinder>& token) = 0;
+    virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) = 0;
 
     /* Gets the input dispatcher configuration. */
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
@@ -349,9 +349,6 @@
      */
     virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
 
-    virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
-            const sp<InputChannel>& toChannel) = 0;
-
     /* Registers input channels that may be used as targets for input events.
      * If inputWindowHandle is null, and displayId is not ADISPLAY_ID_NONE,
      * the channel will receive a copy of all input events form the specific displayId.
@@ -416,8 +413,6 @@
     virtual void setInputFilterEnabled(bool enabled);
 
     virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
-    virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
-            const sp<InputChannel>& toChannel);
 
     virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
             int32_t displayId);
@@ -633,7 +628,8 @@
         uint32_t seq;
         bool handled;
         sp<InputChannel> inputChannel;
-        sp<IBinder> token;
+        sp<IBinder> oldToken;
+        sp<IBinder> newToken;
     };
 
     // Generic queue implementation.
@@ -1163,7 +1159,8 @@
             nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
     void onDispatchCycleBrokenLocked(
             nsecs_t currentTime, const sp<Connection>& connection);
-    void onFocusChangedLocked(const sp<InputWindowHandle>& newFocus);
+    void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
+            const sp<InputWindowHandle>& newFocus);
     void onANRLocked(
             nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
             const sp<InputWindowHandle>& windowHandle,
@@ -1190,7 +1187,7 @@
     void traceOutboundQueueLengthLocked(const sp<Connection>& connection);
     void traceWaitQueueLengthLocked(const sp<Connection>& connection);
 
-    sp<InputReporter> mReporter;
+    sp<InputReporterInterface> mReporter;
 };
 
 /* Enqueues and dispatches input events, endlessly. */
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index b4eb370..b349c73 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -71,8 +71,8 @@
 NotifyMotionArgs::NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId,
         uint32_t source, int32_t displayId, uint32_t policyFlags,
         int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
-        int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
-        uint32_t pointerCount,
+        int32_t buttonState, MotionClassification classification,
+        int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
         float xPrecision, float yPrecision, nsecs_t downTime,
         const std::vector<TouchVideoFrame>& videoFrames) :
@@ -80,7 +80,7 @@
         displayId(displayId), policyFlags(policyFlags),
         action(action), actionButton(actionButton),
         flags(flags), metaState(metaState), buttonState(buttonState),
-        edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
+        classification(classification), edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
         pointerCount(pointerCount),
         xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime),
         videoFrames(videoFrames) {
@@ -95,7 +95,7 @@
         source(other.source), displayId(other.displayId), policyFlags(other.policyFlags),
         action(other.action), actionButton(other.actionButton), flags(other.flags),
         metaState(other.metaState), buttonState(other.buttonState),
-        edgeFlags(other.edgeFlags),
+        classification(other.classification), edgeFlags(other.edgeFlags),
         deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
         xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime),
         videoFrames(other.videoFrames) {
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 33bf163..2b31f6e 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2834,7 +2834,8 @@
                 NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                         mSource, displayId, policyFlags,
                         AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
-                        metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                        metaState, buttonState,
+                        MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                         /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                         mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
                 getListener()->notifyMotion(&releaseArgs);
@@ -2843,7 +2844,7 @@
 
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
                 displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,
-                AMOTION_EVENT_EDGE_FLAG_NONE,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
@@ -2855,7 +2856,8 @@
                 buttonState |= actionButton;
                 NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                         mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS,
-                        actionButton, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                        actionButton, 0, metaState, buttonState,
+                        MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                         /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                         mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
                 getListener()->notifyMotion(&pressArgs);
@@ -2869,7 +2871,8 @@
                 && (mSource == AINPUT_SOURCE_MOUSE)) {
             NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                    metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                    metaState, currentButtonState,
+                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                     /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
             getListener()->notifyMotion(&hoverArgs);
@@ -2883,7 +2886,7 @@
             NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags,
                     AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
-                    AMOTION_EVENT_EDGE_FLAG_NONE,
+                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                     /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
             getListener()->notifyMotion(&scrollArgs);
@@ -3014,8 +3017,8 @@
 
         NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0,
-                AMOTION_EVENT_EDGE_FLAG_NONE,
+                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, /* buttonState */ 0,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, 0, /* videoFrames */ {});
         getListener()->notifyMotion(&scrollArgs);
@@ -5413,7 +5416,7 @@
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, mPointerGesture.downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
@@ -6338,8 +6341,8 @@
         // Send up.
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6352,8 +6355,8 @@
         // Send hover exit.
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6368,7 +6371,8 @@
             // Send down.
             NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags,
-                    AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
+                    AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState,
+                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                     /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
@@ -6379,8 +6383,8 @@
         // Send move.
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6395,8 +6399,8 @@
             NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags,
                     AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
-                    mCurrentRawState.buttonState, 0,
-                    /* deviceTimestamp */ 0,
+                    mCurrentRawState.buttonState, MotionClassification::NONE,
+                    AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
                     mPointerSimple.downTime, /* videoFrames */ {});
@@ -6407,8 +6411,8 @@
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
-                mCurrentRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                mCurrentRawState.buttonState, MotionClassification::NONE,
+                AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6429,8 +6433,8 @@
 
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &pointerCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6497,8 +6501,8 @@
     std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
     NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
             source, displayId, policyFlags,
-            action, actionButton, flags, metaState, buttonState, edgeFlags,
-            deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
+            action, actionButton, flags, metaState, buttonState, MotionClassification::NONE,
+            edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
             xPrecision, yPrecision, downTime, std::move(frames));
     getListener()->notifyMotion(&args);
 }
@@ -7422,9 +7426,9 @@
 
     NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
             AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags,
-            AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-            /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
-            0, 0, 0, /* videoFrames */ {});
+            AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE,
+            AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
+            &pointerProperties, &pointerCoords, 0, 0, 0, /* videoFrames */ {});
     getListener()->notifyMotion(&args);
 }
 
diff --git a/services/inputflinger/InputReporter.cpp b/services/inputflinger/InputReporter.cpp
index cf4220f..8d3153c 100644
--- a/services/inputflinger/InputReporter.cpp
+++ b/services/inputflinger/InputReporter.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,12 +14,18 @@
  * limitations under the License.
  */
 
-#include "InputReporter.h"
+#include "InputReporterInterface.h"
 
 namespace android {
 
 // --- InputReporter ---
 
+class InputReporter : public InputReporterInterface {
+public:
+    void reportUnhandledKey(uint32_t sequenceNum) override;
+    void reportDroppedKey(uint32_t sequenceNum) override;
+};
+
 void InputReporter::reportUnhandledKey(uint32_t sequenceNum) {
   // do nothing
 }
@@ -28,7 +34,7 @@
   // do nothing
 }
 
-sp<InputReporter> createInputReporter() {
+sp<InputReporterInterface> createInputReporter() {
   return new InputReporter();
 }
 
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 2442cc0..53247a0 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -99,6 +99,10 @@
     int32_t flags;
     int32_t metaState;
     int32_t buttonState;
+    /**
+     * Classification of the current touch gesture
+     */
+    MotionClassification classification;
     int32_t edgeFlags;
     /**
      * A timestamp in the input device's time base, not the platform's.
@@ -120,7 +124,7 @@
     NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
             int32_t displayId, uint32_t policyFlags,
             int32_t action, int32_t actionButton, int32_t flags,
-            int32_t metaState, int32_t buttonState,
+            int32_t metaState, int32_t buttonState, MotionClassification classification,
             int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
             const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime,
diff --git a/services/inputflinger/include/InputReporter.h b/services/inputflinger/include/InputReporterInterface.h
similarity index 74%
rename from services/inputflinger/include/InputReporter.h
rename to services/inputflinger/include/InputReporterInterface.h
index c86dcda..906d7f2 100644
--- a/services/inputflinger/include/InputReporter.h
+++ b/services/inputflinger/include/InputReporterInterface.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _UI_INPUT_REPORTER_H
-#define _UI_INPUT_REPORTER_H
+#ifndef _UI_INPUT_REPORTER_INTERFACE_H
+#define _UI_INPUT_REPORTER_INTERFACE_H
 
 #include <utils/RefBase.h>
 
@@ -25,9 +25,9 @@
  * The interface used by the InputDispatcher to report information about input events after
  * it is sent to the application, such as if a key is unhandled or dropped.
  */
-class InputReporter: public virtual RefBase {
+class InputReporterInterface : public virtual RefBase {
 protected:
-    virtual ~InputReporter() { }
+    virtual ~InputReporterInterface() { }
 
 public:
     // Report a key that was not handled by the system or apps.
@@ -35,19 +35,19 @@
     //   - The event was not handled and there is no fallback key; or
     //   - The event was not handled and it has a fallback key,
     //       but the fallback key was not handled.
-    virtual void reportUnhandledKey(uint32_t sequenceNum);
+    virtual void reportUnhandledKey(uint32_t sequenceNum) = 0;
 
     // Report a key that was dropped by InputDispatcher.
     // A key can be dropped for several reasons. See the enum
     // InputDispatcher::DropReason for details.
-    virtual void reportDroppedKey(uint32_t sequenceNum);
+    virtual void reportDroppedKey(uint32_t sequenceNum) = 0;
 };
 
 /*
  * Factory method for InputReporter.
  */
-sp<InputReporter> createInputReporter();
+sp<InputReporterInterface> createInputReporter();
 
 } // namespace android
 
-#endif // _UI_INPUT_REPORTER_H
+#endif // _UI_INPUT_REPORTER_INTERFACE_H
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 26f01b7..3edec40 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -63,7 +63,7 @@
     virtual void notifyInputChannelBroken(const sp<IBinder>&) {
     }
 
-    virtual void notifyFocusChanged(const sp<IBinder>&) {
+    virtual void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) {
     }
 
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
@@ -160,70 +160,70 @@
         pointerCoords[i].clear();
     }
 
+    // Some constants commonly used below
+    constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+    constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
+    constexpr int32_t metaState = AMETA_NONE;
+    constexpr MotionClassification classification = MotionClassification::NONE;
+
     // Rejects undefined motion actions.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            /*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with undefined action.";
 
     // Rejects pointer down with invalid index.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer down index too large.";
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer down index too small.";
 
     // Rejects pointer up with invalid index.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too large.";
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too small.";
 
     // Rejects motion events with invalid number of pointers.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 0, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with 0 pointers.";
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -233,20 +233,18 @@
 
     // Rejects motion events with invalid pointer ids.
     pointerProperties[0].id = -1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer ids less than 0.";
 
     pointerProperties[0].id = MAX_POINTER_ID + 1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -255,10 +253,9 @@
     // Rejects motion events with duplicate pointer ids.
     pointerProperties[0].id = 1;
     pointerProperties[1].id = 1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 2, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -460,7 +457,8 @@
     // Define a valid motion down event.
     event.initialize(DEVICE_ID, source, displayId,
             AMOTION_EVENT_ACTION_DOWN, /* actionButton */0, /* flags */ 0, /* edgeFlags */ 0,
-            AMETA_NONE, /* buttonState */ 0, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
+            AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
+            /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
             /* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties,
             pointerCoords);
 
@@ -517,7 +515,7 @@
     sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
             ADISPLAY_ID_DEFAULT);
 
-    // Set focus application.
+    // Set focused application.
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
     // Expect one focus window exist in display.
@@ -535,6 +533,32 @@
     windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
 }
 
+TEST_F(InputDispatcherTest, SetInputWindow_FocusPriority) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
+            ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
+            ADISPLAY_ID_DEFAULT);
+
+    // Set focused application.
+    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+    // Display has two focused windows. Add them to inputWindowsHandles in z-order (top most first)
+    windowTop->setFocus();
+    windowSecond->setFocus();
+    Vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.add(windowTop);
+    inputWindowHandles.add(windowSecond);
+
+    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+            << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+    // Top focused window should receive event.
+    windowTop->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+    windowSecond->assertNoEvents();
+}
+
 TEST_F(InputDispatcherTest, SetInputWindow_InputWindowInfo) {
     sp<FakeApplicationHandle> application = new FakeApplicationHandle();
 
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 9b2cd50..189ae36 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -35,6 +35,7 @@
 using namespace android::hardware::sensors::V1_0::implementation;
 using android::hardware::sensors::V2_0::ISensorsCallback;
 using android::hardware::sensors::V2_0::EventQueueFlagBits;
+using android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
 using android::hardware::hidl_vec;
 using android::hardware::Return;
 using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
@@ -94,6 +95,8 @@
 SensorDevice::SensorDevice()
         : mHidlTransportErrors(20),
           mRestartWaiter(new HidlServiceRegistrationWaiter()),
+          mEventQueueFlag(nullptr),
+          mWakeLockQueueFlag(nullptr),
           mReconnecting(false) {
     if (!connectHidlService()) {
         return;
@@ -137,6 +140,11 @@
         hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
         mEventQueueFlag = nullptr;
     }
+
+    if (mWakeLockQueueFlag != nullptr) {
+        hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+        mWakeLockQueueFlag = nullptr;
+    }
 }
 
 bool SensorDevice::connectHidlService() {
@@ -198,10 +206,16 @@
                 SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT,
                 true /* configureEventFlagWord */);
 
+        hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
         hardware::EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag);
 
+        hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+        hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(),
+                                             &mWakeLockQueueFlag);
+
         CHECK(mSensors != nullptr && mEventQueue != nullptr &&
-                mWakeLockQueue != nullptr && mEventQueueFlag != nullptr);
+                mWakeLockQueue != nullptr && mEventQueueFlag != nullptr &&
+                mWakeLockQueueFlag != nullptr);
 
         status_t status = StatusFromResult(checkReturn(mSensors->initialize(
                 *mEventQueue->getDesc(),
@@ -512,9 +526,12 @@
 }
 
 void SensorDevice::writeWakeLockHandled(uint32_t count) {
-    if (mSensors != nullptr && mSensors->supportsMessageQueues() &&
-            !mWakeLockQueue->write(&count)) {
-        ALOGW("Failed to write wake lock handled");
+    if (mSensors != nullptr && mSensors->supportsMessageQueues()) {
+        if (mWakeLockQueue->write(&count)) {
+            mWakeLockQueueFlag->wake(asBaseType(WakeLockQueueFlagBits::DATA_WRITTEN));
+        } else {
+            ALOGW("Failed to write wake lock handled");
+        }
     }
 }
 
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index e1024ac..2a69654 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -238,6 +238,7 @@
     std::unique_ptr<WakeLockQueue> mWakeLockQueue;
 
     hardware::EventFlag* mEventQueueFlag;
+    hardware::EventFlag* mWakeLockQueueFlag;
 
     std::array<Event, SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
 
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 3dee0c0..5b3bbca 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -55,6 +55,7 @@
         "libui",
         "libinput",
         "libutils",
+        "libutilscallstack",
     ],
     static_libs: [
         "libcompositionengine",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 4e4d7dd..164a3a6 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -176,7 +176,7 @@
 
     if (!blackOutLayer) {
         // TODO: we could be more subtle with isFixedSize()
-        const bool useFiltering = needsFiltering(renderArea) || isFixedSize();
+        const bool useFiltering = needsFiltering() || renderArea.needsFiltering() || isFixedSize();
 
         // Query the texture matrix given our current filtering mode.
         float textureMatrix[16];
@@ -597,8 +597,11 @@
     return true;
 }
 
-bool BufferLayer::needsFiltering(const RenderArea& renderArea) const {
-    return mNeedsFiltering || renderArea.needsFiltering();
+bool BufferLayer::needsFiltering() const {
+    const auto displayFrame = getBE().compositionInfo.hwc.displayFrame;
+    const auto sourceCrop = getBE().compositionInfo.hwc.sourceCrop;
+    return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
+            sourceCrop.getWidth() != displayFrame.getWidth();
 }
 
 void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
@@ -621,17 +624,19 @@
      * minimal value)? Or, we could make GL behave like HWC -- but this feel
      * like more of a hack.
      */
-    const Rect bounds{computeBounds()}; // Rounds from FloatRect
 
-    ui::Transform t = getTransform();
-    Rect win = bounds;
-    const int bufferWidth = getBufferSize(s).getWidth();
-    const int bufferHeight = getBufferSize(s).getHeight();
+    // Convert to Rect so that bounds are clipped to integers.
+    const Rect win{computeCrop(Rect::INVALID_RECT)};
+    // computeCrop() returns the cropping rectangle in buffer space, so we
+    // shouldn't use getBufferSize() since that may return a rectangle specified
+    // in layer space. Otherwise we may compute incorrect texture coordinates.
+    const float bufWidth = float(mActiveBuffer->getWidth());
+    const float bufHeight = float(mActiveBuffer->getHeight());
 
-    const float left = float(win.left) / float(bufferWidth);
-    const float top = float(win.top) / float(bufferHeight);
-    const float right = float(win.right) / float(bufferWidth);
-    const float bottom = float(win.bottom) / float(bufferHeight);
+    const float left = win.left / bufWidth;
+    const float top = win.top / bufHeight;
+    const float right = win.right / bufWidth;
+    const float bottom = win.bottom / bufHeight;
 
     // TODO: we probably want to generate the texture coords with the mesh
     // here we assume that we only have 4 vertices
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index be16cf5..e3b7f2f 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -167,9 +167,11 @@
     // from GLES
     const uint32_t mTextureName;
 
+    bool mRefreshPending{false};
+
 private:
-    // needsLinearFiltering - true if this surface's state requires filtering
-    bool needsFiltering(const RenderArea& renderArea) const;
+    // Returns true if this layer requires filtering
+    bool needsFiltering() const;
 
     // drawing
     void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
@@ -184,8 +186,6 @@
     // The texture used to draw the layer in GLES composition mode
     mutable renderengine::Texture mTexture;
 
-    bool mRefreshPending{false};
-
     Rect getBufferSize(const State& s) const override;
 };
 
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 5a61122..42021d1 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -352,6 +352,14 @@
 // Interface implementation for BufferLayerConsumer::ContentsChangedListener
 // -----------------------------------------------------------------------
 
+void BufferQueueLayer::fakeVsync() {
+    mRefreshPending = false;
+    bool ignored = false;
+    latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
+    usleep(16000);
+    releasePendingBuffer(systemTime());
+}
+
 void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
     // Add this buffer from our internal queue tracker
     { // Autolock scope
@@ -390,10 +398,7 @@
     // If this layer is orphaned, then we run a fake vsync pulse so that
     // dequeueBuffer doesn't block indefinitely.
     if (isRemovedFromCurrentState()) {
-        bool ignored = false;
-        latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
-        usleep(16000);
-        releasePendingBuffer(systemTime());
+        fakeVsync();
     } else {
         mFlinger->signalLayerUpdate();
     }
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index ae0b705..d7c3f6a 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -137,6 +137,8 @@
     // thread-safe
     std::atomic<int32_t> mQueuedFrames{0};
     std::atomic<bool> mSidebandStreamChanged{false};
+
+    void fakeVsync();
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e0d9d23..2132f59 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -48,10 +48,28 @@
 // Interface implementation for Layer
 // -----------------------------------------------------------------------
 void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
-    // The transaction completed callback can only be sent if the release fence from the PREVIOUS
-    // frame has fired. In practice, we should never actually wait on the previous release fence
-    // but we should store it just in case.
-    mPreviousReleaseFence = releaseFence;
+    // The previous release fence notifies the client that SurfaceFlinger is done with the previous
+    // buffer that was presented on this layer. The first transaction that came in this frame that
+    // replaced the previous buffer on this layer needs this release fence, because the fence will
+    // let the client know when that previous buffer is removed from the screen.
+    //
+    // Every other transaction on this layer does not need a release fence because no other
+    // Transactions that were set on this layer this frame are going to have their preceeding buffer
+    // removed from the display this frame.
+    //
+    // For example, if we have 3 transactions this frame. The first transaction doesn't contain a
+    // buffer so it doesn't need a previous release fence because the layer still needs the previous
+    // buffer. The second transaction contains a buffer so it needs a previous release fence because
+    // the previous buffer will be released this frame. The third transaction also contains a
+    // buffer. It replaces the buffer in the second transaction. The buffer in the second
+    // transaction will now no longer be presented so it is released immediately and the third
+    // transaction doesn't need a previous release fence.
+    for (auto& handle : mDrawingState.callbackHandles) {
+        if (handle->releasePreviousBuffer) {
+            handle->previousReleaseFence = releaseFence;
+            break;
+        }
+    }
 }
 
 void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
@@ -60,7 +78,10 @@
 }
 
 void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
-    return;
+    mFlinger->getTransactionCompletedThread().addPresentedCallbackHandles(
+            mDrawingState.callbackHandles);
+
+    mDrawingState.callbackHandles = {};
 }
 
 bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
@@ -257,14 +278,14 @@
 
             // Notify the transaction completed thread that there is a pending latched callback
             // handle
-            mFlinger->getTransactionCompletedThread().registerPendingLatchedCallbackHandle(handle);
+            mFlinger->getTransactionCompletedThread().registerPendingCallbackHandle(handle);
 
             // Store so latched time and release fence can be set
             mCurrentState.callbackHandles.push_back(handle);
 
         } else { // If this layer will NOT need to be relatched and presented this frame
             // Notify the transaction completed thread this handle is done
-            mFlinger->getTransactionCompletedThread().addUnlatchedCallbackHandle(handle);
+            mFlinger->getTransactionCompletedThread().addUnpresentedCallbackHandle(handle);
         }
     }
 
@@ -504,9 +525,9 @@
         return BAD_VALUE;
     }
 
-    mFlinger->getTransactionCompletedThread()
-            .addLatchedCallbackHandles(getDrawingState().callbackHandles, latchTime,
-                                       mPreviousReleaseFence);
+    for (auto& handle : mDrawingState.callbackHandles) {
+        handle->latchTime = latchTime;
+    }
 
     // Handle sync fences
     if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 4f6fb1c..0e447d8 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -95,6 +95,26 @@
                                  ownerUid, handle, gbp, &parent);
 }
 
+status_t Client::createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+                                         PixelFormat format, uint32_t flags,
+                                         const sp<IGraphicBufferProducer>& parent,
+                                         int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
+                                         sp<IGraphicBufferProducer>* gbp) {
+    if (mFlinger->authenticateSurfaceTexture(parent) == false) {
+        return BAD_VALUE;
+    }
+
+    const auto& layer = (static_cast<MonitoredProducer*>(parent.get()))->getLayer();
+    if (layer == nullptr) {
+        return BAD_VALUE;
+    }
+
+    sp<IBinder> parentHandle = layer->getHandle();
+
+    return createSurface(name, w, h, format, flags, parentHandle, windowType, ownerUid, handle,
+                         gbp);
+}
+
 status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
     sp<Layer> layer = getLayerUser(handle);
     if (layer == nullptr) {
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index d0051de..0f5ee4c 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -58,6 +58,12 @@
             sp<IBinder>* handle,
             sp<IGraphicBufferProducer>* gbp);
 
+    virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+                                             PixelFormat format, uint32_t flags,
+                                             const sp<IGraphicBufferProducer>& parent,
+                                             int32_t windowType, int32_t ownerUid,
+                                             sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp);
+
     virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
 
     virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index d1b1697..aecde9f 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -39,7 +39,7 @@
     bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
 
 protected:
-    FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
+    FloatRect computeCrop(const Rect& /*windowbounds*/) const override { return {}; }
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 2d91c68..03eafd5 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -40,13 +40,12 @@
 
 class BufferHandle {
 public:
-    BufferHandle(const native_handle_t* buffer)
-    {
+    explicit BufferHandle(const native_handle_t* buffer) {
         // nullptr is not a valid handle to HIDL
         mHandle = (buffer) ? buffer : native_handle_init(mStorage, 0, 0);
     }
 
-    operator const hidl_handle&() const
+    operator const hidl_handle&() const // NOLINT(google-explicit-constructor)
     {
         return mHandle;
     }
@@ -80,7 +79,7 @@
         }
     }
 
-    operator const hidl_handle&() const
+    operator const hidl_handle&() const // NOLINT(google-explicit-constructor)
     {
         return mHandle;
     }
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 9d0d8d9..ba3d2a6 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -285,7 +285,7 @@
 // Composer is a wrapper to IComposer, a proxy to server-side composer.
 class Composer final : public Hwc2::Composer {
 public:
-    Composer(const std::string& serviceName);
+    explicit Composer(const std::string& serviceName);
     ~Composer() override;
 
     std::vector<IComposer::Capability> getCapabilities() override;
@@ -418,7 +418,7 @@
 private:
     class CommandWriter : public CommandWriterBase {
     public:
-        CommandWriter(uint32_t initialMaxSize);
+        explicit CommandWriter(uint32_t initialMaxSize);
         ~CommandWriter() override;
 
         void setLayerInfo(uint32_t type, uint32_t appId);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3f2d10a..ee49610 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -380,7 +380,7 @@
     return size;
 }
 
-Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& display) const {
+Rect Layer::computeInitialCrop(const Rect& windowBounds) const {
     // the crop is the area of the window that gets cropped, but not
     // scaled in any ways.
     const State& s(getDrawingState());
@@ -391,12 +391,17 @@
     // pixels in the buffer.
 
     FloatRect activeCropFloat = computeBounds();
-    ui::Transform t = getTransform();
-    // Transform to screen space.
-    activeCropFloat = t.transform(activeCropFloat);
-    activeCropFloat = activeCropFloat.intersect(display->getViewport().toFloatRect());
-    // Back to layer space to work with the content crop.
-    activeCropFloat = t.inverse().transform(activeCropFloat);
+
+    // If we have valid window boundaries then we need to crop to the window
+    // boundaries in layer space.
+    if (windowBounds.isValid()) {
+        const ui::Transform t = getTransform();
+        // Transform to screen space.
+        activeCropFloat = t.transform(activeCropFloat);
+        activeCropFloat = activeCropFloat.intersect(windowBounds.toFloatRect());
+        // Back to layer space to work with the content crop.
+        activeCropFloat = t.inverse().transform(activeCropFloat);
+    }
     // This needs to be here as transform.transform(Rect) computes the
     // transformed rect and then takes the bounding box of the result before
     // returning. This means
@@ -426,7 +431,7 @@
     cropCoords[3] = vec2(win.right, win.top);
 }
 
-FloatRect Layer::computeCrop(const sp<const DisplayDevice>& display) const {
+FloatRect Layer::computeCrop(const Rect& windowBounds) const {
     // the content crop is the area of the content that gets scaled to the
     // layer's size. This is in buffer space.
     FloatRect crop = getContentCrop().toFloatRect();
@@ -434,7 +439,7 @@
     // In addition there is a WM-specified crop we pull from our drawing state.
     const State& s(getDrawingState());
 
-    Rect activeCrop = computeInitialCrop(display);
+    Rect activeCrop = computeInitialCrop(windowBounds);
     Rect bufferSize = getBufferSize(s);
 
     // Transform the window crop to match the buffer coordinate system,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2e75088..7bc7a82 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -671,12 +671,22 @@
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
 
-    virtual FloatRect computeCrop(const sp<const DisplayDevice>& display) const;
+    // Computes the crop applied to this layer. windowBounds is the boundary of
+    // layer-stack space, so the cropping rectangle will be clipped to those
+    // bounds in that space. The crop rectangle is returned in buffer space. If
+    // windowBounds is invalid, then it is ignored.
+    virtual FloatRect computeCrop(const Rect& windowBounds) const;
+
+    // See the above method, but pulls the window boundaries from the display.
+    FloatRect computeCrop(const sp<const DisplayDevice>& display) const {
+        return computeCrop(display->getViewport());
+    }
     // Compute the initial crop as specified by parent layers and the
     // SurfaceControl for this layer. Does not include buffer crop from the
     // IGraphicBufferProducer client, as that should not affect child clipping.
     // Returns in screen space.
-    Rect computeInitialCrop(const sp<const DisplayDevice>& display) const;
+    Rect computeInitialCrop(const Rect& windowBounds) const;
+
     /**
      * Setup rounded corners coordinates of this layer, taking into account the layer bounds and
      * crop coordinates, transforming them into layer space.
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 1683982..7b25adb 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -43,8 +43,12 @@
 
 // ---------------------------------------------------------------------------
 
-EventThreadConnection::EventThreadConnection(EventThread* eventThread)
-      : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {}
+EventThreadConnection::EventThreadConnection(EventThread* eventThread,
+                                             ResyncCallback resyncCallback)
+      : resyncCallback(std::move(resyncCallback)),
+        count(-1),
+        mEventThread(eventThread),
+        mChannel(gui::BitTube::DefaultSize) {}
 
 EventThreadConnection::~EventThreadConnection() {
     // do nothing here -- clean-up will happen automatically
@@ -67,7 +71,13 @@
 }
 
 void EventThreadConnection::requestNextVsync() {
-    mEventThread->requestNextVsync(this);
+    ATRACE_NAME("requestNextVsync");
+    mEventThread->requestNextVsync(this, true);
+}
+
+void EventThreadConnection::requestNextVsyncForHWC() {
+    ATRACE_NAME("requestNextVsyncForHWC");
+    mEventThread->requestNextVsync(this, false);
 }
 
 status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
@@ -82,26 +92,21 @@
 namespace impl {
 
 EventThread::EventThread(std::unique_ptr<VSyncSource> src,
-                         const ResyncWithRateLimitCallback& resyncWithRateLimitCallback,
                          const InterceptVSyncsCallback& interceptVSyncsCallback,
                          const ResetIdleTimerCallback& resetIdleTimerCallback,
                          const char* threadName)
-      : EventThread(nullptr, std::move(src), resyncWithRateLimitCallback, interceptVSyncsCallback,
-                    threadName) {
+      : EventThread(nullptr, std::move(src), interceptVSyncsCallback, threadName) {
     mResetIdleTimer = resetIdleTimerCallback;
 }
 
-EventThread::EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
-                         InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
-      : EventThread(src, nullptr, resyncWithRateLimitCallback, interceptVSyncsCallback,
-                    threadName) {}
+EventThread::EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
+                         const char* threadName)
+      : EventThread(src, nullptr, interceptVSyncsCallback, threadName) {}
 
 EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
-                         ResyncWithRateLimitCallback resyncWithRateLimitCallback,
                          InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
       : mVSyncSource(src),
         mVSyncSourceUnique(std::move(uniqueSrc)),
-        mResyncWithRateLimitCallback(resyncWithRateLimitCallback),
         mInterceptVSyncsCallback(interceptVSyncsCallback) {
     if (src == nullptr) {
         mVSyncSource = mVSyncSourceUnique.get();
@@ -144,8 +149,8 @@
     mVSyncSource->setPhaseOffset(phaseOffset);
 }
 
-sp<EventThreadConnection> EventThread::createEventConnection() const {
-    return new EventThreadConnection(const_cast<EventThread*>(this));
+sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const {
+    return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback));
 }
 
 status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
@@ -184,16 +189,18 @@
     }
 }
 
-void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (mResetIdleTimer) {
+void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection, bool reset) {
+    if (mResetIdleTimer && reset) {
+        ATRACE_NAME("resetIdleTimer");
         mResetIdleTimer();
     }
 
-    if (mResyncWithRateLimitCallback) {
-        mResyncWithRateLimitCallback();
+    if (connection->resyncCallback) {
+        connection->resyncCallback();
     }
 
+    std::lock_guard<std::mutex> lock(mMutex);
+
     if (connection->count < 0) {
         connection->count = 0;
         mCondition.notify_all();
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 66f54bd..a411885 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -44,6 +44,8 @@
 
 // ---------------------------------------------------------------------------
 
+using ResyncCallback = std::function<void()>;
+
 class VSyncSource {
 public:
     class Callback {
@@ -60,7 +62,7 @@
 
 class EventThreadConnection : public BnDisplayEventConnection {
 public:
-    explicit EventThreadConnection(EventThread* eventThread);
+    EventThreadConnection(EventThread* eventThread, ResyncCallback resyncCallback);
     virtual ~EventThreadConnection();
 
     virtual status_t postEvent(const DisplayEventReceiver::Event& event);
@@ -68,6 +70,12 @@
     status_t stealReceiveChannel(gui::BitTube* outChannel) override;
     status_t setVsyncRate(uint32_t count) override;
     void requestNextVsync() override; // asynchronous
+    // Requesting Vsync for HWC does not reset the idle timer, since HWC requires a refresh
+    // in order to update the configs.
+    void requestNextVsyncForHWC();
+
+    // Called in response to requestNextVsync.
+    const ResyncCallback resyncCallback;
 
     // count >= 1 : continuous event. count is the vsync rate
     // count == 0 : one-shot event that has not fired
@@ -87,7 +95,8 @@
 
     virtual ~EventThread();
 
-    virtual sp<EventThreadConnection> createEventConnection() const = 0;
+    virtual sp<EventThreadConnection> createEventConnection(
+            ResyncCallback resyncCallback) const = 0;
 
     // called before the screen is turned off from main thread
     virtual void onScreenReleased() = 0;
@@ -105,31 +114,32 @@
     virtual status_t registerDisplayEventConnection(
             const sp<EventThreadConnection>& connection) = 0;
     virtual void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) = 0;
-    virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
+    // 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;
 };
 
 namespace impl {
 
 class EventThread : public android::EventThread, private VSyncSource::Callback {
 public:
-    using ResyncWithRateLimitCallback = std::function<void()>;
     using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
     using ResetIdleTimerCallback = std::function<void()>;
 
     // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
-    EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
-                InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
+    EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
+                const char* threadName);
     EventThread(std::unique_ptr<VSyncSource> src,
-                const ResyncWithRateLimitCallback& resyncWithRateLimitCallback,
                 const InterceptVSyncsCallback& interceptVSyncsCallback,
                 const ResetIdleTimerCallback& resetIdleTimerCallback, const char* threadName);
     ~EventThread();
 
-    sp<EventThreadConnection> createEventConnection() const override;
+    sp<EventThreadConnection> createEventConnection(ResyncCallback resyncCallback) const override;
 
     status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
     void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) override;
-    void requestNextVsync(const sp<EventThreadConnection>& connection) override;
+    void requestNextVsync(const sp<EventThreadConnection>& connection,
+                          bool resetIdleTimer) override;
 
     // called before the screen is turned off from main thread
     void onScreenReleased() override;
@@ -149,7 +159,6 @@
 
     // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
     EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
-                ResyncWithRateLimitCallback resyncWithRateLimitCallback,
                 InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
 
 
@@ -166,11 +175,13 @@
     // Implements VSyncSource::Callback
     void onVSyncEvent(nsecs_t timestamp) override;
 
+    // Acquires mutex and requests next vsync.
+    void requestNextVsyncInternal(const sp<EventThreadConnection>& connection) EXCLUDES(mMutex);
+
     // TODO(b/113612090): Once the Scheduler is complete this pointer will become obsolete.
     VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
     std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
     // constants
-    const ResyncWithRateLimitCallback mResyncWithRateLimitCallback;
     const InterceptVSyncsCallback mInterceptVSyncsCallback;
 
     std::thread mThread;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 36403cc..75a410b 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -85,7 +85,8 @@
     mHandler = new Handler(*this);
 }
 
-void MessageQueue::setEventThread(android::EventThread* eventThread) {
+void MessageQueue::setEventThread(android::EventThread* eventThread,
+                                  ResyncCallback resyncCallback) {
     if (mEventThread == eventThread) {
         return;
     }
@@ -95,7 +96,7 @@
     }
 
     mEventThread = eventThread;
-    mEvents = eventThread->createEventConnection();
+    mEvents = eventThread->createEventConnection(std::move(resyncCallback));
     mEvents->stealReceiveChannel(&mEventTube);
     mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
                    this);
@@ -148,6 +149,10 @@
     mEvents->requestNextVsync();
 }
 
+void MessageQueue::invalidateForHWC() {
+    mEvents->requestNextVsyncForHWC();
+}
+
 void MessageQueue::refresh() {
     mHandler->dispatchRefresh();
 }
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 24a3834..56a00c0 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -29,12 +29,12 @@
 #include <private/gui/BitTube.h>
 
 #include "Barrier.h"
+#include "EventThread.h"
 
 #include <functional>
 
 namespace android {
 
-class EventThread;
 class SurfaceFlinger;
 
 // ---------------------------------------------------------------------------
@@ -86,11 +86,12 @@
 
     virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
     // TODO(akrulec): Remove this function once everything is migrated to Scheduler.
-    virtual void setEventThread(EventThread* events) = 0;
+    virtual void setEventThread(EventThread* events, ResyncCallback resyncCallback) = 0;
     virtual void setEventConnection(const sp<EventThreadConnection>& connection) = 0;
     virtual void waitMessage() = 0;
     virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
     virtual void invalidate() = 0;
+    virtual void invalidateForHWC() = 0;
     virtual void refresh() = 0;
 };
 
@@ -126,7 +127,7 @@
 public:
     ~MessageQueue() override = default;
     void init(const sp<SurfaceFlinger>& flinger) override;
-    void setEventThread(android::EventThread* events) override;
+    void setEventThread(android::EventThread* events, ResyncCallback resyncCallback) override;
     void setEventConnection(const sp<EventThreadConnection>& connection) override;
 
     void waitMessage() override;
@@ -134,6 +135,9 @@
 
     // sends INVALIDATE message at next VSYNC
     void invalidate() override;
+
+    // sends INVALIDATE message at next VSYNC, without resetting the idle timer in the Scheduler
+    void invalidateForHWC();
     // sends REFRESH message at next VSYNC
     void refresh() override;
 };
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index c363ba5..0d587dd 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -86,39 +86,38 @@
 Scheduler::~Scheduler() = default;
 
 sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
-        const std::string& connectionName, int64_t phaseOffsetNs,
-        impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+        const std::string& connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
         impl::EventThread::InterceptVSyncsCallback interceptCallback) {
     const int64_t id = sNextId++;
     ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
 
     std::unique_ptr<EventThread> eventThread =
-            makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs, resyncCallback,
+            makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
                             interceptCallback);
     auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
-                                                   eventThread->createEventConnection(),
+                                                   eventThread->createEventConnection(
+                                                           std::move(resyncCallback)),
                                                    std::move(eventThread));
+
     mConnections.insert(std::make_pair(id, std::move(connection)));
     return mConnections[id]->handle;
 }
 
 std::unique_ptr<EventThread> Scheduler::makeEventThread(
         const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
-        impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
         impl::EventThread::InterceptVSyncsCallback interceptCallback) {
     const std::string sourceName = connectionName + "Source";
     std::unique_ptr<VSyncSource> eventThreadSource =
             std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, sourceName.c_str());
     const std::string threadName = connectionName + "Thread";
-    return std::make_unique<impl::EventThread>(std::move(eventThreadSource), resyncCallback,
-                                               interceptCallback, [this] { resetIdleTimer(); },
-                                               threadName.c_str());
+    return std::make_unique<impl::EventThread>(std::move(eventThreadSource), interceptCallback,
+                                               [this] { resetIdleTimer(); }, threadName.c_str());
 }
 
 sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
-        const sp<Scheduler::ConnectionHandle>& handle) {
+        const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) {
     RETURN_VALUE_IF_INVALID(nullptr);
-    return mConnections[handle->id]->thread->createEventConnection();
+    return mConnections[handle->id]->thread->createEventConnection(std::move(resyncCallback));
 }
 
 EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -238,6 +237,16 @@
     mLayerHistory.incrementCounter();
 }
 
+void Scheduler::setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback) {
+    std::lock_guard<std::mutex> lock(mCallbackLock);
+    mExpiredTimerCallback = expiredTimerCallback;
+}
+
+void Scheduler::setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback) {
+    std::lock_guard<std::mutex> lock(mCallbackLock);
+    mResetTimerCallback = resetTimerCallback;
+}
+
 void Scheduler::updateFrameSkipping(const int64_t skipCount) {
     ATRACE_INT("FrameSkipCount", skipCount);
     if (mSkipCount != skipCount) {
@@ -314,12 +323,12 @@
     // TODO(b/113612090): This are current numbers from trial and error while running videos
     // from YouTube at 24, 30, and 60 fps.
     if (mean > 14 && mean < 18) {
-        ATRACE_INT("FPS", 60);
+        ATRACE_INT("MediaFPS", 60);
     } else if (mean > 31 && mean < 34) {
-        ATRACE_INT("FPS", 30);
+        ATRACE_INT("MediaFPS", 30);
         return;
     } else if (mean > 39 && mean < 42) {
-        ATRACE_INT("FPS", 24);
+        ATRACE_INT("MediaFPS", 24);
     }
 }
 
@@ -328,13 +337,19 @@
         mIdleTimer->reset();
         ATRACE_INT("ExpiredIdleTimer", 0);
     }
+
+    std::lock_guard<std::mutex> lock(mCallbackLock);
+    if (mResetTimerCallback) {
+        mResetTimerCallback();
+    }
 }
 
 void Scheduler::expiredTimerCallback() {
-    // TODO(b/113612090): Each time a timer expired, we should record the information into
-    // a circular buffer. Once this has happened a given amount (TBD) of times, we can comfortably
-    // say that the device is sitting in idle.
-    ATRACE_INT("ExpiredIdleTimer", 1);
+    std::lock_guard<std::mutex> lock(mCallbackLock);
+    if (mExpiredTimerCallback) {
+        mExpiredTimerCallback();
+        ATRACE_INT("ExpiredIdleTimer", 1);
+    }
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 9d7dd4d..ba18d21 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -36,6 +36,9 @@
 
 class Scheduler {
 public:
+    using ExpiredIdleTimerCallback = std::function<void()>;
+    using ResetIdleTimerCallback = std::function<void()>;
+
     // Enum to indicate whether to start the transaction early, or at vsync time.
     enum class TransactionStart { EARLY, NORMAL };
 
@@ -70,11 +73,11 @@
 
     /** Creates an EventThread connection. */
     sp<ConnectionHandle> createConnection(
-            const std::string& connectionName, int64_t phaseOffsetNs,
-            impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+            const std::string& connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
             impl::EventThread::InterceptVSyncsCallback interceptCallback);
 
-    sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle);
+    sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
+                                                             ResyncCallback resyncCallback);
 
     // Getter methods.
     EventThread* getEventThread(const sp<ConnectionHandle>& handle);
@@ -111,11 +114,14 @@
                                      const std::string layerName);
     // Increments counter in the layer history to indicate that SF has started a new frame.
     void incrementFrameCounter();
+    // Callback that gets invoked once the idle timer expires.
+    void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback);
+    // Callback that gets invoked once the idle timer is reset.
+    void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback);
 
 protected:
     virtual std::unique_ptr<EventThread> makeEventThread(
             const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
-            impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
             impl::EventThread::InterceptVSyncsCallback interceptCallback);
 
 private:
@@ -173,6 +179,10 @@
     // interval, a callback is fired. Set this variable to >0 to use this feature.
     int64_t mSetIdleTimerMs = 0;
     std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
+
+    std::mutex mCallbackLock;
+    ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
+    ResetIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/StartPropertySetThread.h b/services/surfaceflinger/StartPropertySetThread.h
index a64c21b..bbdcde2 100644
--- a/services/surfaceflinger/StartPropertySetThread.h
+++ b/services/surfaceflinger/StartPropertySetThread.h
@@ -33,7 +33,7 @@
 // Any property_set() will block during init stage so need to be offloaded
 // to this thread. see b/63844978.
 public:
-    StartPropertySetThread(bool timestampPropertyValue);
+    explicit StartPropertySetThread(bool timestampPropertyValue);
     status_t Start();
 private:
     virtual bool threadLoop();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dc82b32..1af1112 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -17,15 +17,16 @@
 // #define LOG_NDEBUG 0
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <stdint.h>
 #include <sys/types.h>
-#include <algorithm>
 #include <errno.h>
-#include <math.h>
-#include <mutex>
 #include <dlfcn.h>
-#include <inttypes.h>
-#include <stdatomic.h>
+
+#include <algorithm>
+#include <cinttypes>
+#include <cmath>
+#include <cstdint>
+#include <functional>
+#include <mutex>
 #include <optional>
 
 #include <cutils/properties.h>
@@ -52,6 +53,7 @@
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/PixelFormat.h>
 #include <ui/UiConfig.h>
+#include <utils/CallStack.h>
 #include <utils/StopWatch.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
@@ -617,6 +619,8 @@
 
     Mutex::Autolock _l(mStateLock);
 
+    auto resyncCallback = makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
+
     // start the EventThread
     if (mUseScheduler) {
         mScheduler = getFactory().createScheduler([this](bool enabled) {
@@ -625,12 +629,11 @@
 
         mAppConnectionHandle =
                 mScheduler->createConnection("appConnection", SurfaceFlinger::vsyncPhaseOffsetNs,
-                                             [this] { resyncWithRateLimit(); },
+                                             resyncCallback,
                                              impl::EventThread::InterceptVSyncsCallback());
         mSfConnectionHandle =
                 mScheduler->createConnection("sfConnection", SurfaceFlinger::sfVsyncPhaseOffsetNs,
-                                             [this] { resyncWithRateLimit(); },
-                                             [this](nsecs_t timestamp) {
+                                             resyncCallback, [this](nsecs_t timestamp) {
                                                  mInterceptor->saveVSyncEvent(timestamp);
                                              });
 
@@ -643,7 +646,6 @@
                                                  SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
         mEventThread =
                 std::make_unique<impl::EventThread>(mEventThreadSource.get(),
-                                                    [this] { resyncWithRateLimit(); },
                                                     impl::EventThread::InterceptVSyncsCallback(),
                                                     "appEventThread");
         mSfEventThreadSource =
@@ -652,12 +654,11 @@
 
         mSFEventThread =
                 std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
-                                                    [this] { resyncWithRateLimit(); },
                                                     [this](nsecs_t timestamp) {
                                                         mInterceptor->saveVSyncEvent(timestamp);
                                                     },
                                                     "sfEventThread");
-        mEventQueue->setEventThread(mSFEventThread.get());
+        mEventQueue->setEventThread(mSFEventThread.get(), std::move(resyncCallback));
         mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
     }
 
@@ -729,6 +730,11 @@
         ALOGE("Run StartPropertySetThread failed!");
     }
 
+    if (mUseScheduler) {
+        mScheduler->setExpiredIdleTimerCallback([this]() { setRefreshRateTo(60.f /* fps */); });
+        mScheduler->setResetIdleTimerCallback([this]() { setRefreshRateTo(90.f /* fps */); });
+    }
+
     ALOGV("Done initializing");
 }
 
@@ -934,14 +940,47 @@
     return display->getActiveConfig();
 }
 
-void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, int mode) {
+status_t SurfaceFlinger::setActiveConfigAsync(const sp<IBinder>& displayToken, int mode) {
+    ATRACE_NAME("setActiveConfigAsync");
+    postMessageAsync(new LambdaMessage(
+            [=]() NO_THREAD_SAFETY_ANALYSIS { setActiveConfigInternal(displayToken, mode); }));
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
+    ATRACE_NAME("setActiveConfigSync");
+    postMessageSync(new LambdaMessage(
+            [&]() NO_THREAD_SAFETY_ANALYSIS { setActiveConfigInternal(displayToken, mode); }));
+    return NO_ERROR;
+}
+
+void SurfaceFlinger::setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) {
+    Vector<DisplayInfo> configs;
+    getDisplayConfigs(displayToken, &configs);
+    if (mode < 0 || mode >= static_cast<int>(configs.size())) {
+        ALOGE("Attempt to set active config %d for display with %zu configs", mode, configs.size());
+        return;
+    }
+
+    const auto display = getDisplayDevice(displayToken);
+    if (!display) {
+        ALOGE("Attempt to set active config %d for invalid display token %p", mode,
+              displayToken.get());
+        return;
+    }
     if (display->isVirtual()) {
-        ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+        ALOGW("Attempt to set active config %d for virtual display", mode);
+        return;
+    }
+    int currentDisplayPowerMode = display->getPowerMode();
+    if (currentDisplayPowerMode != HWC_POWER_MODE_NORMAL) {
+        // Don't change active config when in AoD.
         return;
     }
 
     int currentMode = display->getActiveConfig();
     if (mode == currentMode) {
+        // Don't update config if we are already running in the desired mode.
         return;
     }
 
@@ -950,29 +989,9 @@
 
     display->setActiveConfig(mode);
     getHwComposer().setActiveConfig(*displayId, mode);
-}
 
-status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
-    postMessageSync(new LambdaMessage([&] {
-        Vector<DisplayInfo> configs;
-        getDisplayConfigs(displayToken, &configs);
-        if (mode < 0 || mode >= static_cast<int>(configs.size())) {
-            ALOGE("Attempt to set active config %d for display with %zu configs", mode,
-                  configs.size());
-            return;
-        }
-        const auto display = getDisplayDevice(displayToken);
-        if (!display) {
-            ALOGE("Attempt to set active config %d for invalid display token %p", mode,
-                  displayToken.get());
-        } else if (display->isVirtual()) {
-            ALOGW("Attempt to set active config %d for virtual display", mode);
-        } else {
-            setActiveConfigInternal(display, mode);
-        }
-    }));
-
-    return NO_ERROR;
+    ATRACE_INT("ActiveConfigMode", mode);
+    resyncToHardwareVsync(true, getVsyncPeriod());
 }
 
 status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
@@ -1136,6 +1155,14 @@
                                                      outStats);
 }
 
+status_t SurfaceFlinger::getProtectedContentSupport(bool* outSupported) const {
+    if (!outSupported) {
+        return BAD_VALUE;
+    }
+    *outSupported = getRenderEngine().supportsProtectedContent();
+    return NO_ERROR;
+}
+
 status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
     postMessageSync(new LambdaMessage([&] {
         Mutex::Autolock _l(mStateLock);
@@ -1144,6 +1171,8 @@
             return;
         }
 
+        auto resyncCallback = makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
+
         // TODO(akrulec): Part of the Injector should be refactored, so that it
         // can be passed to Scheduler.
         if (enable) {
@@ -1151,14 +1180,14 @@
             if (mVSyncInjector.get() == nullptr) {
                 mVSyncInjector = std::make_unique<InjectVSyncSource>();
                 mInjectorEventThread = std::make_unique<
-                        impl::EventThread>(mVSyncInjector.get(), [this] { resyncWithRateLimit(); },
+                        impl::EventThread>(mVSyncInjector.get(),
                                            impl::EventThread::InterceptVSyncsCallback(),
                                            "injEventThread");
             }
-            mEventQueue->setEventThread(mInjectorEventThread.get());
+            mEventQueue->setEventThread(mInjectorEventThread.get(), std::move(resyncCallback));
         } else {
             ALOGV("VSync Injections disabled");
-            mEventQueue->setEventThread(mSFEventThread.get());
+            mEventQueue->setEventThread(mSFEventThread.get(), std::move(resyncCallback));
         }
 
         mInjectVSyncs = enable;
@@ -1215,17 +1244,22 @@
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
         ISurfaceComposer::VsyncSource vsyncSource) {
+    auto resyncCallback = makeResyncCallback([this] {
+        Mutex::Autolock lock(mStateLock);
+        return getVsyncPeriod();
+    });
+
     if (mUseScheduler) {
         if (vsyncSource == eVsyncSourceSurfaceFlinger) {
-            return mScheduler->createDisplayEventConnection(mSfConnectionHandle);
+            return mScheduler->createDisplayEventConnection(mSfConnectionHandle, resyncCallback);
         } else {
-            return mScheduler->createDisplayEventConnection(mAppConnectionHandle);
+            return mScheduler->createDisplayEventConnection(mAppConnectionHandle, resyncCallback);
         }
     } else {
         if (vsyncSource == eVsyncSourceSurfaceFlinger) {
-            return mSFEventThread->createEventConnection();
+            return mSFEventThread->createEventConnection(resyncCallback);
         } else {
-            return mEventThread->createEventConnection();
+            return mEventThread->createEventConnection(resyncCallback);
         }
     }
 }
@@ -1269,6 +1303,16 @@
     } while (true);
 }
 
+nsecs_t SurfaceFlinger::getVsyncPeriod() const {
+    const auto displayId = getInternalDisplayId();
+    if (!displayId || !getHwComposer().isConnected(*displayId)) {
+        return 0;
+    }
+
+    const auto config = getHwComposer().getActiveConfig(*displayId);
+    return config ? config->getVsyncPeriod() : 0;
+}
+
 void SurfaceFlinger::enableHardwareVsync() {
     Mutex::Autolock _l(mHWVsyncLock);
     if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
@@ -1278,7 +1322,7 @@
     }
 }
 
-void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {
+void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
     Mutex::Autolock _l(mHWVsyncLock);
 
     if (makeAvailable) {
@@ -1293,14 +1337,10 @@
         return;
     }
 
-    const auto displayId = getInternalDisplayId();
-    if (!displayId || !getHwComposer().isConnected(*displayId)) {
+    if (period <= 0) {
         return;
     }
 
-    const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
-    const nsecs_t period = activeConfig->getVsyncPeriod();
-
     if (mUseScheduler) {
         mScheduler->setVsyncPeriod(period);
     } else {
@@ -1327,16 +1367,15 @@
     }
 }
 
-void SurfaceFlinger::resyncWithRateLimit() {
+void SurfaceFlinger::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
     static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
 
-    // No explicit locking is needed here since EventThread holds a lock while calling this method
-    static nsecs_t sLastResyncAttempted = 0;
     const nsecs_t now = systemTime();
-    if (now - sLastResyncAttempted > kIgnoreDelay) {
-        resyncToHardwareVsync(false);
+    const nsecs_t last = lastResyncTime.exchange(now);
+
+    if (now - last > kIgnoreDelay) {
+        flinger.resyncToHardwareVsync(false, getVsyncPeriod());
     }
-    sLastResyncAttempted = now;
 }
 
 void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -1382,6 +1421,49 @@
     *compositorTiming = getBE().mCompositorTiming;
 }
 
+void SurfaceFlinger::setRefreshRateTo(float newFps) {
+    const auto displayId = getInternalDisplayId();
+    if (!displayId || mBootStage != BootStage::FINISHED) {
+        return;
+    }
+    // TODO(b/113612090): There should be a message queue flush here. Because this esentially
+    // runs on a mainthread, we cannot call postMessageSync. This can be resolved in a better
+    // manner, once the setActiveConfig is synchronous, and is executed at a known time in a
+    // refresh cycle.
+
+    // Don't do any updating if the current fps is the same as the new one.
+    const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
+    const nsecs_t currentVsyncPeriod = activeConfig->getVsyncPeriod();
+    if (currentVsyncPeriod == 0) {
+        return;
+    }
+    // TODO(b/113612090): Consider having an enum value for correct refresh rates, rather than
+    // floating numbers.
+    const float currentFps = 1e9 / currentVsyncPeriod;
+    if (std::abs(currentFps - newFps) <= 1) {
+        return;
+    }
+
+    auto configs = getHwComposer().getConfigs(*displayId);
+    for (int i = 0; i < configs.size(); i++) {
+        const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
+        if (vsyncPeriod == 0) {
+            continue;
+        }
+        const float fps = 1e9 / vsyncPeriod;
+        // TODO(b/113612090): There should be a better way at determining which config
+        // has the right refresh rate.
+        if (std::abs(fps - newFps) <= 1) {
+            const auto display = getBuiltInDisplay(HWC_DISPLAY_PRIMARY);
+            if (!display) return;
+            // This is posted in async function to avoid deadlock when getDisplayDevice
+            // requires mStateLock.
+            setActiveConfigAsync(display, i);
+            ATRACE_INT("FPS", newFps);
+        }
+    }
+}
+
 void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
                                        HWC2::Connection connection) {
     ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
@@ -1413,7 +1495,7 @@
     if (sequenceId != getBE().mComposerSequenceId) {
         return;
     }
-    repaintEverything();
+    repaintEverythingForHWC();
 }
 
 void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) {
@@ -1493,9 +1575,8 @@
     setPowerModeInternal(display, currentDisplayPowerMode);
 
     // Reset the timing values to account for the period of the swapped in HWC
-    const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
-    const nsecs_t period = activeConfig->getVsyncPeriod();
-    mAnimFrameTracker.setDisplayRefreshPeriod(period);
+    const nsecs_t vsyncPeriod = getVsyncPeriod();
+    mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
 
     // The present fences returned from vr_hwc are not an accurate
     // representation of vsync times.
@@ -1509,10 +1590,10 @@
 
     // Use phase of 0 since phase is not known.
     // Use latency of 0, which will snap to the ideal latency.
-    DisplayStatInfo stats{0 /* vsyncTime */, period /* vsyncPeriod */};
+    DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
     setCompositorTimingSnapped(stats, 0);
 
-    resyncToHardwareVsync(false);
+    resyncToHardwareVsync(false, vsyncPeriod);
 
     mRepaintEverything = true;
     setTransactionFlags(eDisplayTransactionNeeded);
@@ -1876,22 +1957,78 @@
     getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
 }
 
+// debug patch for b/119477596 - add stack guards to catch stack
+// corruptions and disable clang optimizations.
+// The code below is temporary and planned to be removed once stack
+// corruptions are found.
+#pragma clang optimize off
+class StackGuard {
+public:
+    StackGuard(const char* name, const char* func, int line) {
+        guarders.reserve(MIN_CAPACITY);
+        guarders.push_back({this, name, func, line});
+        validate();
+    }
+    ~StackGuard() {
+        for (auto i = guarders.end() - 1; i >= guarders.begin(); --i) {
+            if (i->guard == this) {
+                guarders.erase(i);
+                break;
+            }
+        }
+    }
+
+    static void validate() {
+        for (const auto& guard : guarders) {
+            if (guard.guard->cookie != COOKIE_VALUE) {
+                ALOGE("%s:%d: Stack corruption detected at %s", guard.func, guard.line, guard.name);
+                CallStack stack(LOG_TAG);
+                abort();
+            }
+        }
+    }
+
+private:
+    uint64_t cookie = COOKIE_VALUE;
+    static constexpr uint64_t COOKIE_VALUE = 0xc0febebedeadbeef;
+    static constexpr size_t MIN_CAPACITY = 16;
+
+    struct GuarderElement {
+        StackGuard* guard;
+        const char* name;
+        const char* func;
+        int line;
+    };
+
+    static std::vector<GuarderElement> guarders;
+};
+std::vector<StackGuard::GuarderElement> StackGuard::guarders;
+
+#define DEFINE_STACK_GUARD(__n) StackGuard __n##StackGuard(#__n, __FUNCTION__, __LINE__);
+
+#define ASSERT_ON_STACK_GUARD() StackGuard::validate();
 void SurfaceFlinger::postComposition()
 {
+    DEFINE_STACK_GUARD(begin);
     ATRACE_CALL();
     ALOGV("postComposition");
 
     // Release any buffers which were replaced this frame
     nsecs_t dequeueReadyTime = systemTime();
+    DEFINE_STACK_GUARD(dequeueReadyTime);
     for (auto& layer : mLayersWithQueuedFrames) {
         layer->releasePendingBuffer(dequeueReadyTime);
     }
+    ASSERT_ON_STACK_GUARD();
 
     // |mStateLock| not needed as we are on the main thread
     const auto display = getDefaultDisplayDeviceLocked();
+    DEFINE_STACK_GUARD(display);
 
     getBE().mGlCompositionDoneTimeline.updateSignalTimes();
     std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
+    DEFINE_STACK_GUARD(glCompositionDoneFenceTime);
+
     if (display && getHwComposer().hasClientComposition(display->getId())) {
         glCompositionDoneFenceTime =
                 std::make_shared<FenceTime>(display->getClientTargetAcquireFence());
@@ -1900,13 +2037,17 @@
         glCompositionDoneFenceTime = FenceTime::NO_FENCE;
     }
 
+    ASSERT_ON_STACK_GUARD();
+
     getBE().mDisplayTimeline.updateSignalTimes();
     mPreviousPresentFence =
             display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE;
     auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
+    DEFINE_STACK_GUARD(presentFenceTime);
     getBE().mDisplayTimeline.push(presentFenceTime);
 
     DisplayStatInfo stats;
+    DEFINE_STACK_GUARD(stats);
     if (mUseScheduler) {
         mScheduler->getDisplayStatInfo(&stats);
     } else {
@@ -1914,34 +2055,46 @@
         stats.vsyncPeriod = mPrimaryDispSync->getPeriod();
     }
 
+    ASSERT_ON_STACK_GUARD();
+
     // We use the mRefreshStartTime which might be sampled a little later than
     // when we started doing work for this frame, but that should be okay
     // since updateCompositorTiming has snapping logic.
     updateCompositorTiming(stats, mRefreshStartTime, presentFenceTime);
     CompositorTiming compositorTiming;
+    DEFINE_STACK_GUARD(compositorTiming);
+
     {
         std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
+        DEFINE_STACK_GUARD(lock);
         compositorTiming = getBE().mCompositorTiming;
+
+        ASSERT_ON_STACK_GUARD();
     }
 
     mDrawingState.traverseInZOrder([&](Layer* layer) {
         bool frameLatched = layer->onPostComposition(display->getId(), glCompositionDoneFenceTime,
                                                      presentFenceTime, compositorTiming);
+        DEFINE_STACK_GUARD(frameLatched);
         if (frameLatched) {
             recordBufferingStats(layer->getName().string(),
                     layer->getOccupancyHistory(false));
         }
+        ASSERT_ON_STACK_GUARD();
     });
 
     if (presentFenceTime->isValid()) {
+        ASSERT_ON_STACK_GUARD();
         if (mUseScheduler) {
             mScheduler->addPresentFence(presentFenceTime);
+            ASSERT_ON_STACK_GUARD();
         } else {
             if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
                 enableHardwareVsync();
             } else {
                 disableHardwareVsync(false);
             }
+            ASSERT_ON_STACK_GUARD();
         }
     }
 
@@ -1955,61 +2108,86 @@
         }
     }
 
+    ASSERT_ON_STACK_GUARD();
+
     if (mAnimCompositionPending) {
         mAnimCompositionPending = false;
 
         if (presentFenceTime->isValid()) {
             mAnimFrameTracker.setActualPresentFence(
                     std::move(presentFenceTime));
+
+            ASSERT_ON_STACK_GUARD();
         } else if (display && getHwComposer().isConnected(*display->getId())) {
             // The HWC doesn't support present fences, so use the refresh
             // timestamp instead.
             const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(*display->getId());
+            DEFINE_STACK_GUARD(presentTime);
+
             mAnimFrameTracker.setActualPresentTime(presentTime);
+            ASSERT_ON_STACK_GUARD();
         }
         mAnimFrameTracker.advanceFrame();
     }
 
+    ASSERT_ON_STACK_GUARD();
+
     mTimeStats->incrementTotalFrames();
     if (mHadClientComposition) {
         mTimeStats->incrementClientCompositionFrames();
     }
 
+    ASSERT_ON_STACK_GUARD();
+
     mTimeStats->setPresentFenceGlobal(presentFenceTime);
 
+    ASSERT_ON_STACK_GUARD();
+
     if (display && getHwComposer().isConnected(*display->getId()) && !display->isPoweredOn()) {
         return;
     }
 
     nsecs_t currentTime = systemTime();
+    DEFINE_STACK_GUARD(currentTime);
     if (mHasPoweredOff) {
         mHasPoweredOff = false;
     } else {
         nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
+        DEFINE_STACK_GUARD(elapsedTime);
         size_t numPeriods = static_cast<size_t>(elapsedTime / stats.vsyncPeriod);
+        DEFINE_STACK_GUARD(numPeriods);
         if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
             getBE().mFrameBuckets[numPeriods] += elapsedTime;
         } else {
             getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] += elapsedTime;
         }
         getBE().mTotalTime += elapsedTime;
+
+        ASSERT_ON_STACK_GUARD();
     }
     getBE().mLastSwapTime = currentTime;
+    ASSERT_ON_STACK_GUARD();
 
     {
         std::lock_guard lock(mTexturePoolMutex);
+        DEFINE_STACK_GUARD(lock);
         const size_t refillCount = mTexturePoolSize - mTexturePool.size();
+        DEFINE_STACK_GUARD(refillCount);
         if (refillCount > 0) {
             const size_t offset = mTexturePool.size();
             mTexturePool.resize(mTexturePoolSize);
             getRenderEngine().genTextures(refillCount, mTexturePool.data() + offset);
             ATRACE_INT("TexturePoolSize", mTexturePool.size());
         }
+        ASSERT_ON_STACK_GUARD();
     }
 
     mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
     mTransactionCompletedThread.sendCallbacks();
+
+    ASSERT_ON_STACK_GUARD();
 }
+#pragma clang optimize on // b/119477596
 
 void SurfaceFlinger::rebuildLayerStacks() {
     ATRACE_CALL();
@@ -3963,8 +4141,11 @@
 // ---------------------------------------------------------------------------
 
 void SurfaceFlinger::onInitializeDisplays() {
-    const auto displayToken = getInternalDisplayToken();
-    if (!displayToken) return;
+    const auto display = getDefaultDisplayDeviceLocked();
+    if (!display) return;
+
+    const sp<IBinder> token = display->getDisplayToken().promote();
+    LOG_ALWAYS_FATAL_IF(token == nullptr);
 
     // reset screen orientation and use primary layer stack
     Vector<ComposerState> state;
@@ -3972,7 +4153,7 @@
     DisplayState d;
     d.what = DisplayState::eDisplayProjectionChanged |
              DisplayState::eLayerStackChanged;
-    d.token = displayToken;
+    d.token = token;
     d.layerStack = 0;
     d.orientation = DisplayState::eOrientationDefault;
     d.frame.makeInvalid();
@@ -3982,24 +4163,21 @@
     displays.add(d);
     setTransactionState(state, displays, 0, nullptr, mInputWindowCommands);
 
-    const auto display = getDisplayDevice(displayToken);
-    if (!display) return;
-
     setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
 
-    const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
-    const nsecs_t period = activeConfig->getVsyncPeriod();
-    mAnimFrameTracker.setDisplayRefreshPeriod(period);
+    const nsecs_t vsyncPeriod = getVsyncPeriod();
+    mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
 
     // Use phase of 0 since phase is not known.
     // Use latency of 0, which will snap to the ideal latency.
-    DisplayStatInfo stats{0 /* vsyncTime */, period /* vsyncPeriod */};
+    DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
     setCompositorTimingSnapped(stats, 0);
 }
 
 void SurfaceFlinger::initializeDisplays() {
     // Async since we may be called from the main thread.
-    postMessageAsync(new LambdaMessage([this] { onInitializeDisplays(); }));
+    postMessageAsync(
+            new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
 }
 
 void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
@@ -4033,7 +4211,7 @@
             } else {
                 mEventThread->onScreenAcquired();
             }
-            resyncToHardwareVsync(true);
+            resyncToHardwareVsync(true, getVsyncPeriod());
         }
 
         mVisibleRegionsDirty = true;
@@ -4078,7 +4256,7 @@
             } else {
                 mEventThread->onScreenAcquired();
             }
-            resyncToHardwareVsync(true);
+            resyncToHardwareVsync(true, getVsyncPeriod());
         }
     } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
         // Leave display going to doze
@@ -4108,7 +4286,7 @@
 }
 
 void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
-    postMessageSync(new LambdaMessage([&] {
+    postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS {
         const auto display = getDisplayDevice(displayToken);
         if (!display) {
             ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
@@ -4281,12 +4459,7 @@
         index++;
     }
 
-    if (const auto displayId = getInternalDisplayId();
-        displayId && getHwComposer().isConnected(*displayId)) {
-        const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
-        const nsecs_t period = activeConfig->getVsyncPeriod();
-        StringAppendF(&result, "%" PRId64 "\n", period);
-    }
+    StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriod());
 
     if (name.isEmpty()) {
         mAnimFrameTracker.dumpStats(result);
@@ -4587,22 +4760,16 @@
 
     const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
     const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
-    if (const auto displayId = getInternalDisplayId();
-        displayId && getHwComposer().isConnected(*displayId)) {
-        const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
-        StringAppendF(&result,
-                      "Display %s: app phase %" PRId64 " ns, "
-                      "sf phase %" PRId64 " ns, "
-                      "early app phase %" PRId64 " ns, "
-                      "early sf phase %" PRId64 " ns, "
-                      "early app gl phase %" PRId64 " ns, "
-                      "early sf gl phase %" PRId64 " ns, "
-                      "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
-                      to_string(*displayId).c_str(), vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
-                      appEarlyOffset, sfEarlyOffset, appEarlyGlOffset, sfEarlyGlOffset,
-                      dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
-    }
-    result.append("\n");
+    StringAppendF(&result,
+                  "app phase %" PRId64 " ns, "
+                  "sf phase %" PRId64 " ns, "
+                  "early app phase %" PRId64 " ns, "
+                  "early sf phase %" PRId64 " ns, "
+                  "early app gl phase %" PRId64 " ns, "
+                  "early sf gl phase %" PRId64 " ns, "
+                  "present offset %" PRId64 " ns (refresh %" PRId64 " ns)\n",
+                  vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, appEarlyOffset, sfEarlyOffset,
+                  appEarlyGlOffset, sfEarlyGlOffset, dispSyncPresentTimeOffset, getVsyncPeriod());
 
     // Dump static screen stats
     result.append("\n");
@@ -4847,7 +5014,8 @@
         case SET_TRANSACTION_STATE:
         case CREATE_CONNECTION:
         case GET_COLOR_MANAGEMENT:
-        case GET_COMPOSITION_PREFERENCE: {
+        case GET_COMPOSITION_PREFERENCE:
+        case GET_PROTECTED_CONTENT_SUPPORT: {
             return OK;
         }
         case CAPTURE_LAYERS:
@@ -5177,6 +5345,11 @@
     signalTransaction();
 }
 
+void SurfaceFlinger::repaintEverythingForHWC() {
+    mRepaintEverything = true;
+    mEventQueue->invalidateForHWC();
+}
+
 // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
 class WindowDisconnector {
 public:
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ac730ab..a4bd3e9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -17,63 +17,58 @@
 #ifndef ANDROID_SURFACE_FLINGER_H
 #define ANDROID_SURFACE_FLINGER_H
 
-#include <memory>
-#include <stdint.h>
 #include <sys/types.h>
 
 /*
  * NOTE: Make sure this file doesn't include  anything from <gl/ > or <gl2/ >
  */
 
-#include <cutils/compiler.h>
+#include <android-base/thread_annotations.h>
 #include <cutils/atomic.h>
-
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/SortedVector.h>
-#include <utils/threads.h>
-#include <utils/Trace.h>
-
-#include <ui/FenceTime.h>
-#include <ui/PixelFormat.h>
-#include <math/mat4.h>
-
+#include <cutils/compiler.h>
+#include <gui/BufferQueue.h>
 #include <gui/FrameTimestamps.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerState.h>
-
 #include <gui/OccupancyTracker.h>
-#include <gui/BufferQueue.h>
-
 #include <hardware/hwcomposer_defs.h>
-
+#include <layerproto/LayerProtoHeader.h>
+#include <math/mat4.h>
 #include <serviceutils/PriorityDumper.h>
-
 #include <system/graphics.h>
+#include <ui/FenceTime.h>
+#include <ui/PixelFormat.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/Trace.h>
+#include <utils/threads.h>
 
 #include "Barrier.h"
 #include "DisplayDevice.h"
+#include "DisplayHardware/HWC2.h"
+#include "DisplayHardware/HWComposer.h"
+#include "Effects/Daltonizer.h"
 #include "FrameTracker.h"
 #include "LayerBE.h"
 #include "LayerStats.h"
 #include "LayerVector.h"
-#include "SurfaceFlingerFactory.h"
-#include "SurfaceInterceptor.h"
-#include "SurfaceTracing.h"
-#include "TransactionCompletedThread.h"
-
-#include "DisplayHardware/HWC2.h"
-#include "DisplayHardware/HWComposer.h"
-#include "Effects/Daltonizer.h"
 #include "Scheduler/DispSync.h"
 #include "Scheduler/EventThread.h"
 #include "Scheduler/MessageQueue.h"
 #include "Scheduler/Scheduler.h"
 #include "Scheduler/VSyncModulator.h"
+#include "SurfaceFlingerFactory.h"
+#include "SurfaceInterceptor.h"
+#include "SurfaceTracing.h"
+#include "TransactionCompletedThread.h"
 
+#include <atomic>
+#include <cstdint>
 #include <map>
+#include <memory>
 #include <mutex>
 #include <queue>
 #include <set>
@@ -82,8 +77,6 @@
 #include <unordered_map>
 #include <utility>
 
-#include <layerproto/LayerProtoHeader.h>
-
 using namespace android::surfaceflinger;
 
 namespace android {
@@ -148,10 +141,6 @@
 
     const std::string mHwcServiceName; // "default" for real use, something else for testing.
 
-    // constant members (no synchronization needed for access)
-    EGLContext mEGLContext;
-    EGLDisplay mEGLDisplay;
-
     FenceTimeline mGlCompositionDoneTimeline;
     FenceTimeline mDisplayTimeline;
 
@@ -311,6 +300,9 @@
     // force full composition on all displays
     void repaintEverything();
 
+    // force full composition on all displays without resetting the scheduler idle timer.
+    void repaintEverythingForHWC();
+
     surfaceflinger::Factory& getFactory() { return mFactory; }
 
     // The CompositionEngine encapsulates all composition related interfaces and actions.
@@ -409,77 +401,75 @@
     /* ------------------------------------------------------------------------
      * IBinder interface
      */
-    virtual status_t onTransact(uint32_t code, const Parcel& data,
-        Parcel* reply, uint32_t flags);
-    virtual status_t dump(int fd, const Vector<String16>& args) { return priorityDump(fd, args); }
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
+    status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); }
 
     /* ------------------------------------------------------------------------
      * ISurfaceComposer interface
      */
-    virtual sp<ISurfaceComposerClient> createConnection();
-    virtual sp<IBinder> createDisplay(const String8& displayName, bool secure);
-    virtual void destroyDisplay(const sp<IBinder>& displayToken);
-    virtual sp<IBinder> getBuiltInDisplay(int32_t id);
-    virtual void setTransactionState(const Vector<ComposerState>& state,
-                                     const Vector<DisplayState>& displays, uint32_t flags,
-                                     const sp<IBinder>& applyToken,
-                                     const InputWindowCommands& inputWindowCommands);
-    virtual void bootFinished();
-    virtual bool authenticateSurfaceTexture(
-        const sp<IGraphicBufferProducer>& bufferProducer) const;
-    virtual status_t getSupportedFrameTimestamps(
-            std::vector<FrameEvent>* outSupported) const;
-    virtual sp<IDisplayEventConnection> createDisplayEventConnection(
-            ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp);
-    virtual 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);
-    virtual 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);
-    virtual status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
-    virtual status_t getDisplayConfigs(const sp<IBinder>& displayToken,
-                                       Vector<DisplayInfo>* configs);
-    virtual int getActiveConfig(const sp<IBinder>& displayToken);
-    virtual status_t getDisplayColorModes(const sp<IBinder>& displayToken,
-                                          Vector<ui::ColorMode>* configs);
-    virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken);
-    virtual status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode);
-    virtual void setPowerMode(const sp<IBinder>& displayToken, int mode);
-    virtual status_t setActiveConfig(const sp<IBinder>& displayToken, int id);
-    virtual status_t clearAnimationFrameStats();
-    virtual status_t getAnimationFrameStats(FrameStats* outStats) const;
-    virtual status_t getHdrCapabilities(const sp<IBinder>& displayToken,
-                                        HdrCapabilities* outCapabilities) const;
-    virtual status_t enableVSyncInjections(bool enable);
-    virtual status_t injectVSync(nsecs_t when);
-    virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
-    virtual status_t getColorManagement(bool* outGetColorManagement) const;
+    sp<ISurfaceComposerClient> createConnection() override;
+    sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
+    void destroyDisplay(const sp<IBinder>& displayToken) override;
+    sp<IBinder> getBuiltInDisplay(int32_t id) override;
+    void setTransactionState(const Vector<ComposerState>& state,
+                             const Vector<DisplayState>& displays, uint32_t flags,
+                             const sp<IBinder>& applyToken,
+                             const InputWindowCommands& inputWindowCommands) override;
+    void bootFinished() override;
+    bool authenticateSurfaceTexture(
+            const sp<IGraphicBufferProducer>& bufferProducer) const override;
+    status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override;
+    sp<IDisplayEventConnection> createDisplayEventConnection(
+            ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp) override;
+    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;
+    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;
+    status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
+    status_t getDisplayConfigs(const sp<IBinder>& displayToken,
+                               Vector<DisplayInfo>* configs) override;
+    int getActiveConfig(const sp<IBinder>& displayToken) override;
+    status_t getDisplayColorModes(const sp<IBinder>& displayToken,
+                                  Vector<ui::ColorMode>* configs) override;
+    ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken) override;
+    status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
+    void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
+    status_t setActiveConfig(const sp<IBinder>& displayToken, int id) override;
+    status_t clearAnimationFrameStats() override;
+    status_t getAnimationFrameStats(FrameStats* outStats) const override;
+    status_t getHdrCapabilities(const sp<IBinder>& displayToken,
+                                HdrCapabilities* outCapabilities) const override;
+    status_t enableVSyncInjections(bool enable) override;
+    status_t injectVSync(nsecs_t when) override;
+    status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const override;
+    status_t getColorManagement(bool* outGetColorManagement) const override;
     status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
                                       ui::Dataspace* outWideColorGamutDataspace,
                                       ui::PixelFormat* outWideColorGamutPixelFormat) const override;
-    virtual status_t getDisplayedContentSamplingAttributes(
-            const sp<IBinder>& display, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace,
-            uint8_t* outComponentMask) const override;
-    virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
-                                                      uint8_t componentMask,
-                                                      uint64_t maxFrames) const override;
-    virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
-                                               uint64_t timestamp,
-                                               DisplayedFrameStats* outStats) const override;
+    status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
+                                                   ui::PixelFormat* outFormat,
+                                                   ui::Dataspace* outDataspace,
+                                                   uint8_t* outComponentMask) const override;
+    status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+                                              uint8_t componentMask,
+                                              uint64_t maxFrames) const override;
+    status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+                                       uint64_t timestamp,
+                                       DisplayedFrameStats* outStats) const override;
+    status_t getProtectedContentSupport(bool* outSupported) const override;
 
     /* ------------------------------------------------------------------------
      * DeathRecipient interface
      */
-    virtual void binderDied(const wp<IBinder>& who);
+    void binderDied(const wp<IBinder>& who) override;
 
     /* ------------------------------------------------------------------------
      * RefBase interface
      */
-    virtual void onFirstRef();
+    void onFirstRef() override;
 
     /* ------------------------------------------------------------------------
      * HWC2::ComposerCallback / HWComposer::EventHandler interface
@@ -501,11 +491,13 @@
     void signalRefresh();
 
     // called on the main thread in response to initializeDisplays()
-    void onInitializeDisplays();
+    void onInitializeDisplays() REQUIRES(mStateLock);
+    // setActiveConfigInternal() posted on a main thread for async execution
+    status_t setActiveConfigAsync(const sp<IBinder>& displayToken, int mode);
     // called on the main thread in response to setActiveConfig()
-    void setActiveConfigInternal(const sp<DisplayDevice>& display, int mode);
+    void setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock);
     // called on the main thread in response to setPowerMode()
-    void setPowerModeInternal(const sp<DisplayDevice>& display, int mode);
+    void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
 
     // Called on the main thread in response to setActiveColorMode()
     void setActiveColorModeInternal(const sp<DisplayDevice>& display, ui::ColorMode colorMode,
@@ -701,6 +693,7 @@
 
     void preComposition();
     void postComposition();
+    void getCompositorTiming(CompositorTiming* compositorTiming);
     void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
                                 std::shared_ptr<FenceTime>& presentFenceTime);
     void setCompositorTimingSnapped(const DisplayStatInfo& stats,
@@ -755,14 +748,37 @@
     /* ------------------------------------------------------------------------
      * VSync
      */
+    nsecs_t getVsyncPeriod() const REQUIRES(mStateLock);
     void enableHardwareVsync();
-    void resyncToHardwareVsync(bool makeAvailable);
+    void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
     void disableHardwareVsync(bool makeUnavailable);
 
-public:
-    void resyncWithRateLimit();
-    void getCompositorTiming(CompositorTiming* compositorTiming);
-private:
+    // Sets the refresh rate to newFps by switching active configs, if they are available for
+    // the desired refresh rate.
+    void setRefreshRateTo(float newFps);
+
+    using GetVsyncPeriod = std::function<nsecs_t()>;
+
+    // Stores per-display state about VSYNC.
+    struct VsyncState {
+        explicit VsyncState(SurfaceFlinger& flinger) : flinger(flinger) {}
+
+        void resync(const GetVsyncPeriod&);
+
+        SurfaceFlinger& flinger;
+        std::atomic<nsecs_t> lastResyncTime = 0;
+    };
+
+    const std::shared_ptr<VsyncState> mPrimaryVsyncState{std::make_shared<VsyncState>(*this)};
+
+    auto makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
+        std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
+        return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
+            if (const auto vsync = ptr.lock()) {
+                vsync->resync(getVsyncPeriod);
+            }
+        };
+    }
 
     /* ------------------------------------------------------------------------
      * Debugging & dumpsys
@@ -809,9 +825,11 @@
     }
 
     void listLayersLocked(const Vector<String16>& args, size_t& index, std::string& result) const;
-    void dumpStatsLocked(const Vector<String16>& args, size_t& index, std::string& result) const;
+    void dumpStatsLocked(const Vector<String16>& args, size_t& index, std::string& result) const
+            REQUIRES(mStateLock);
     void clearStatsLocked(const Vector<String16>& args, size_t& index, std::string& result);
-    void dumpAllLocked(const Vector<String16>& args, size_t& index, std::string& result) const;
+    void dumpAllLocked(const Vector<String16>& args, size_t& index, std::string& result) const
+            REQUIRES(mStateLock);
     bool startDdmConnection();
     void appendSfConfigString(std::string& result) const;
 
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index a1a8692..d2b7fe0 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -62,8 +62,7 @@
     mThread = std::thread(&TransactionCompletedThread::threadMain, this);
 }
 
-void TransactionCompletedThread::registerPendingLatchedCallbackHandle(
-        const sp<CallbackHandle>& handle) {
+void TransactionCompletedThread::registerPendingCallbackHandle(const sp<CallbackHandle>& handle) {
     std::lock_guard lock(mMutex);
 
     sp<IBinder> listener = IInterface::asBinder(handle->listener);
@@ -72,19 +71,10 @@
     mPendingTransactions[listener][callbackIds]++;
 }
 
-void TransactionCompletedThread::addLatchedCallbackHandles(
-        const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
-        const sp<Fence>& previousReleaseFence) {
+void TransactionCompletedThread::addPresentedCallbackHandles(
+        const std::deque<sp<CallbackHandle>>& handles) {
     std::lock_guard lock(mMutex);
 
-    // If the previous release fences have not signaled, something as probably gone wrong.
-    // Store the fences and check them again before sending a callback.
-    if (previousReleaseFence &&
-        previousReleaseFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
-        ALOGD("release fence from the previous frame has not signaled");
-        mPreviousReleaseFences.push_back(previousReleaseFence);
-    }
-
     for (const auto& handle : handles) {
         auto listener = mPendingTransactions.find(IInterface::asBinder(handle->listener));
         auto& pendingCallbacks = listener->second;
@@ -101,17 +91,16 @@
             ALOGE("there are more latched callbacks than there were registered callbacks");
         }
 
-        addCallbackHandle(handle, latchTime);
+        addCallbackHandle(handle);
     }
 }
 
-void TransactionCompletedThread::addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle) {
+void TransactionCompletedThread::addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle) {
     std::lock_guard lock(mMutex);
     addCallbackHandle(handle);
 }
 
-void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
-                                                   nsecs_t latchTime) {
+void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
     const sp<IBinder> listener = IInterface::asBinder(handle->listener);
 
     // If we don't already have a reference to this listener, linkToDeath so we get a notification
@@ -128,9 +117,9 @@
     listenerStats.listener = handle->listener;
 
     auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
-    transactionStats.latchTime = latchTime;
+    transactionStats.latchTime = handle->latchTime;
     transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
-                                               handle->releasePreviousBuffer);
+                                               handle->previousReleaseFence);
 }
 
 void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
@@ -151,15 +140,6 @@
     while (mKeepRunning) {
         mConditionVariable.wait(mMutex);
 
-        // We should never hit this case. The release fences from the previous frame should have
-        // signaled long before the current frame is presented.
-        for (const auto& fence : mPreviousReleaseFences) {
-            status_t status = fence->wait(100);
-            if (status != NO_ERROR) {
-                ALOGE("previous release fence has not signaled, err %d", status);
-            }
-        }
-
         // For each listener
         auto it = mListenerStats.begin();
         while (it != mListenerStats.end()) {
@@ -200,7 +180,6 @@
 
         if (mPresentFence) {
             mPresentFence.clear();
-            mPreviousReleaseFences.clear();
         }
     }
 }
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index 1612f69..f49306d 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -40,7 +40,9 @@
     sp<IBinder> surfaceControl;
 
     bool releasePreviousBuffer = false;
+    sp<Fence> previousReleaseFence;
     nsecs_t acquireTime = -1;
+    nsecs_t latchTime = -1;
 };
 
 class TransactionCompletedThread {
@@ -54,14 +56,13 @@
     // layer has received the CallbackHandle so the TransactionCompletedThread knows not to send
     // a callback for that Listener/Transaction pair until that CallbackHandle has been latched and
     // presented.
-    void registerPendingLatchedCallbackHandle(const sp<CallbackHandle>& handle);
-    // Notifies the TransactionCompletedThread that a pending CallbackHandle has been latched.
-    void addLatchedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
-                                   const sp<Fence>& previousReleaseFence);
+    void registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
+    // Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented.
+    void addPresentedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles);
 
     // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
     // presented this frame.
-    void addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle);
+    void addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
 
     void addPresentFence(const sp<Fence>& presentFence);
 
@@ -70,8 +71,7 @@
 private:
     void threadMain();
 
-    void addCallbackHandle(const sp<CallbackHandle>& handle, nsecs_t latchTime = -1)
-            REQUIRES(mMutex);
+    void addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
 
     class ThreadDeathRecipient : public IBinder::DeathRecipient {
     public:
@@ -110,7 +110,6 @@
     bool mKeepRunning GUARDED_BY(mMutex) = true;
 
     sp<Fence> mPresentFence GUARDED_BY(mMutex);
-    std::vector<sp<Fence>> mPreviousReleaseFences GUARDED_BY(mMutex);
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 991ea36..9339761 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -302,7 +302,7 @@
 
     void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
 
-    ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
+    explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
         mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
     }
 
@@ -2542,6 +2542,7 @@
     enum PreviousBuffer {
         NOT_RELEASED = 0,
         RELEASED,
+        UNKNOWN,
     };
 
     void reset() {
@@ -2596,14 +2597,19 @@
               : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
 
         void verifySurfaceStats(const SurfaceStats& surfaceStats, nsecs_t latchTime) const {
-            const auto& [surfaceControl, acquireTime, releasePreviousBuffer] = surfaceStats;
+            const auto& [surfaceControl, acquireTime, previousReleaseFence] = surfaceStats;
 
             ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
                     << "bad acquire time";
             ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
-            ASSERT_EQ(releasePreviousBuffer,
-                      mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED)
-                    << "bad previous buffer released";
+
+            if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
+                ASSERT_NE(previousReleaseFence, nullptr)
+                        << "failed to set release prev buffer fence";
+            } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) {
+                ASSERT_EQ(previousReleaseFence, nullptr)
+                        << "should not have set released prev buffer fence";
+            }
         }
 
     private:
@@ -3177,13 +3183,11 @@
     Transaction transaction;
     CallbackHelper callback;
     std::vector<ExpectedResult> expectedResults(50);
-    ExpectedResult::PreviousBuffer previousBufferResult =
-            ExpectedResult::PreviousBuffer::NOT_RELEASED;
     for (auto& expected : expectedResults) {
         expected.reset();
         expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
-                            ExpectedResult::Buffer::ACQUIRED, previousBufferResult);
-        previousBufferResult = ExpectedResult::PreviousBuffer::RELEASED;
+                            ExpectedResult::Buffer::ACQUIRED,
+                            ExpectedResult::PreviousBuffer::UNKNOWN);
 
         int err = fillTransaction(transaction, &callback, layer);
         if (err) {
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index a5b522e..a2c0611 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -11,6 +11,7 @@
     shared_libs: [
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
         "android.hardware.power@1.3",
         "libbase",
         "libbinder",
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index 973156a..eeb6efe 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -81,7 +81,7 @@
 
 class DelayedEventGenerator {
 public:
-    DelayedEventGenerator(std::function<void()> onTimerExpired)
+    explicit DelayedEventGenerator(std::function<void()> onTimerExpired)
           : mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {}
 
     ~DelayedEventGenerator() {
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
index c439b7e..a3fb8a6 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
@@ -26,7 +26,7 @@
 
 class FakeComposerService : public IComposer {
 public:
-    FakeComposerService(android::sp<ComposerClient>& client);
+    explicit FakeComposerService(android::sp<ComposerClient>& client);
     virtual ~FakeComposerService();
 
     Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
index 1258a97..7d20d3c 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
@@ -100,10 +100,7 @@
  */
 class TransactionScope : public android::SurfaceComposerClient::Transaction {
 public:
-    TransactionScope(FakeComposerClient& composer) :
-            Transaction(),
-            mComposer(composer) {
-    }
+    explicit TransactionScope(FakeComposerClient& composer) : Transaction(), mComposer(composer) {}
 
     ~TransactionScope() {
         int frameCount = mComposer.getFrameCount();
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
index d7082f3..06ae314 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
@@ -171,7 +171,7 @@
 
 class Hwc2TestBlendMode : public Hwc2TestProperty<hwc2_blend_mode_t> {
 public:
-    Hwc2TestBlendMode(Hwc2TestCoverage coverage);
+    explicit Hwc2TestBlendMode(Hwc2TestCoverage coverage);
 
     std::string dump() const override;
 
@@ -192,8 +192,8 @@
 
 class Hwc2TestColor : public Hwc2TestProperty<hwc_color_t> {
 public:
-    Hwc2TestColor(Hwc2TestCoverage coverage,
-            hwc2_blend_mode_t blendMode = HWC2_BLEND_MODE_NONE);
+    explicit Hwc2TestColor(Hwc2TestCoverage coverage,
+                           hwc2_blend_mode_t blendMode = HWC2_BLEND_MODE_NONE);
 
     std::string dump() const override;
 
@@ -217,7 +217,7 @@
 
 class Hwc2TestComposition : public Hwc2TestProperty<hwc2_composition_t> {
 public:
-    Hwc2TestComposition(Hwc2TestCoverage coverage);
+    explicit Hwc2TestComposition(Hwc2TestCoverage coverage);
 
     std::string dump() const override;
 
@@ -232,7 +232,7 @@
 
 class Hwc2TestDataspace : public Hwc2TestProperty<android::ui::Dataspace> {
 public:
-    Hwc2TestDataspace(Hwc2TestCoverage coverage);
+    explicit Hwc2TestDataspace(Hwc2TestCoverage coverage);
 
     std::string dump() const override;
 
@@ -248,7 +248,7 @@
 
 class Hwc2TestDisplayDimension : public Hwc2TestProperty<UnsignedArea> {
 public:
-    Hwc2TestDisplayDimension(Hwc2TestCoverage coverage);
+    explicit Hwc2TestDisplayDimension(Hwc2TestCoverage coverage);
 
     std::string dump() const;
 
@@ -291,7 +291,7 @@
 
 class Hwc2TestPlaneAlpha : public Hwc2TestProperty<float> {
 public:
-    Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage);
+    explicit Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage);
 
     std::string dump() const override;
 
@@ -306,7 +306,7 @@
 
 class Hwc2TestSourceCrop : public Hwc2TestProperty<hwc_frect_t> {
 public:
-    Hwc2TestSourceCrop(Hwc2TestCoverage coverage, const Area& bufferArea = {0, 0});
+    explicit Hwc2TestSourceCrop(Hwc2TestCoverage coverage, const Area& bufferArea = {0, 0});
 
     std::string dump() const override;
 
@@ -330,7 +330,7 @@
 
 class Hwc2TestSurfaceDamage : public Hwc2TestProperty<hwc_region_t> {
 public:
-    Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage);
+    explicit Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage);
     ~Hwc2TestSurfaceDamage();
 
     std::string dump() const override;
@@ -356,7 +356,7 @@
 
 class Hwc2TestTransform : public Hwc2TestProperty<hwc_transform_t> {
 public:
-    Hwc2TestTransform(Hwc2TestCoverage coverage);
+    explicit Hwc2TestTransform(Hwc2TestCoverage coverage);
 
     std::string dump() const override;
 
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
index 10c8ef0..5a74a6c 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
@@ -29,7 +29,7 @@
 
 class Hwc2TestVirtualDisplay {
 public:
-    Hwc2TestVirtualDisplay(Hwc2TestCoverage coverage);
+    explicit Hwc2TestVirtualDisplay(Hwc2TestCoverage coverage);
 
     std::string dump() const;
 
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index acbed51..c18068f 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -47,10 +47,11 @@
 
 class EventThreadTest : public testing::Test {
 protected:
-    class MockEventThreadConnection : public android::EventThreadConnection {
+    class MockEventThreadConnection : public EventThreadConnection {
     public:
-        explicit MockEventThreadConnection(android::impl::EventThread* eventThread)
-              : android::EventThreadConnection(eventThread) {}
+        MockEventThreadConnection(android::impl::EventThread* eventThread,
+                                  ResyncCallback&& resyncCallback)
+              : EventThreadConnection(eventThread, std::move(resyncCallback)) {}
         MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
     };
 
@@ -113,14 +114,14 @@
 void EventThreadTest::createThread() {
     mThread =
             std::make_unique<android::impl::EventThread>(&mVSyncSource,
-                                                         mResyncCallRecorder.getInvocable(),
                                                          mInterceptVSyncCallRecorder.getInvocable(),
                                                          "unit-test-event-thread");
 }
 
 sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
         ConnectionEventRecorder& recorder) {
-    sp<MockEventThreadConnection> connection = new MockEventThreadConnection(mThread.get());
+    sp<MockEventThreadConnection> connection =
+            new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable());
     EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
     return connection;
 }
@@ -200,7 +201,7 @@
 
 TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
     // Signal that we want the next vsync event to be posted to the connection
-    mThread->requestNextVsync(mConnection);
+    mThread->requestNextVsync(mConnection, false);
 
     // EventThread should immediately request a resync.
     EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 4253ad8..3dd5143 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -8,12 +8,9 @@
 
 #include <mutex>
 
-#include "AsyncCallRecorder.h"
-#include "Scheduler/DispSync.h"
 #include "Scheduler/EventControlThread.h"
 #include "Scheduler/EventThread.h"
 #include "Scheduler/Scheduler.h"
-#include "mock/MockDispSync.h"
 #include "mock/MockEventThread.h"
 
 using testing::_;
@@ -26,7 +23,7 @@
     class MockEventThreadConnection : public android::EventThreadConnection {
     public:
         explicit MockEventThreadConnection(EventThread* eventThread)
-              : EventThreadConnection(eventThread) {}
+              : EventThreadConnection(eventThread, ResyncCallback()) {}
         ~MockEventThreadConnection() = default;
 
         MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel));
@@ -46,7 +43,6 @@
         std::unique_ptr<EventThread> makeEventThread(
                 const std::string& /* connectionName */, DispSync* /* dispSync */,
                 nsecs_t /* phaseOffsetNs */,
-                impl::EventThread::ResyncWithRateLimitCallback /* resyncCallback */,
                 impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
             return std::move(mEventThread);
         }
@@ -61,13 +57,9 @@
     ~SchedulerTest() override;
 
     sp<Scheduler::ConnectionHandle> mConnectionHandle;
-    mock::DispSync* mPrimaryDispSync = new mock::DispSync();
     mock::EventThread* mEventThread;
     std::unique_ptr<MockScheduler> mScheduler;
     sp<MockEventThreadConnection> mEventThreadConnection;
-
-    AsyncCallRecorder<void (*)()> mResyncCallRecorder;
-    AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
 };
 
 SchedulerTest::SchedulerTest() {
@@ -84,12 +76,12 @@
 
     // createConnection call to scheduler makes a createEventConnection call to EventThread. Make
     // sure that call gets executed and returns an EventThread::Connection object.
-    EXPECT_CALL(*mEventThread, createEventConnection())
+    EXPECT_CALL(*mEventThread, createEventConnection(_))
             .WillRepeatedly(Return(mEventThreadConnection));
 
-    mConnectionHandle =
-            mScheduler->createConnection("appConnection", 16, mResyncCallRecorder.getInvocable(),
-                                         mInterceptVSyncCallRecorder.getInvocable());
+    mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(),
+                                                     impl::EventThread::InterceptVSyncsCallback());
+    EXPECT_TRUE(mConnectionHandle != nullptr);
 }
 
 SchedulerTest::~SchedulerTest() {
@@ -102,17 +94,13 @@
 /* ------------------------------------------------------------------------
  * Test cases
  */
-TEST_F(SchedulerTest, canCreateAndDestroyTest) {
-    EXPECT_FALSE(mResyncCallRecorder.waitForCall().has_value());
-    EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall().has_value());
-    EXPECT_EQ(0, mConnectionHandle->id);
-}
 
 TEST_F(SchedulerTest, testNullPtr) {
     // Passing a null pointer for ConnectionHandle is a valid argument. The code doesn't throw any
     // exceptions, just gracefully continues.
     sp<IDisplayEventConnection> returnedValue;
-    ASSERT_NO_FATAL_FAILURE(returnedValue = mScheduler->createDisplayEventConnection(nullptr));
+    ASSERT_NO_FATAL_FAILURE(
+            returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback()));
     EXPECT_TRUE(returnedValue == nullptr);
     EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
     EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
@@ -132,8 +120,9 @@
     sp<Scheduler::ConnectionHandle> connectionHandle = new Scheduler::ConnectionHandle(20);
 
     sp<IDisplayEventConnection> returnedValue;
-    ASSERT_NO_FATAL_FAILURE(returnedValue =
-                                    mScheduler->createDisplayEventConnection(connectionHandle));
+    ASSERT_NO_FATAL_FAILURE(
+            returnedValue =
+                    mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback()));
     EXPECT_TRUE(returnedValue == nullptr);
     EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
     EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
@@ -160,8 +149,9 @@
 
 TEST_F(SchedulerTest, validConnectionHandle) {
     sp<IDisplayEventConnection> returnedValue;
-    ASSERT_NO_FATAL_FAILURE(returnedValue =
-                                    mScheduler->createDisplayEventConnection(mConnectionHandle));
+    ASSERT_NO_FATAL_FAILURE(
+            returnedValue =
+                    mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback()));
     EXPECT_TRUE(returnedValue != nullptr);
     ASSERT_EQ(returnedValue, mEventThreadConnection);
 
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 9ff5e8d..15a8c5a 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -235,9 +235,14 @@
 
     auto setDisplayStateLocked(const DisplayState& s) { return mFlinger->setDisplayStateLocked(s); }
 
-    auto onInitializeDisplays() { return mFlinger->onInitializeDisplays(); }
+    // Allow reading display state without locking, as if called on the SF main thread.
+    auto onInitializeDisplays() NO_THREAD_SAFETY_ANALYSIS {
+        return mFlinger->onInitializeDisplays();
+    }
 
-    auto setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
+    // Allow reading display state without locking, as if called on the SF main thread.
+    auto setPowerModeInternal(const sp<DisplayDevice>& display,
+                              int mode) NO_THREAD_SAFETY_ANALYSIS {
         return mFlinger->setPowerModeInternal(display, mode);
     }
 
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index bb6e183..3242ef1 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -28,7 +28,7 @@
     EventThread();
     ~EventThread() override;
 
-    MOCK_CONST_METHOD0(createEventConnection, sp<EventThreadConnection>());
+    MOCK_CONST_METHOD1(createEventConnection, sp<EventThreadConnection>(ResyncCallback));
     MOCK_METHOD0(onScreenReleased, void());
     MOCK_METHOD0(onScreenAcquired, void());
     MOCK_METHOD2(onHotplugReceived, void(DisplayType, bool));
@@ -37,7 +37,7 @@
     MOCK_METHOD1(registerDisplayEventConnection,
                  status_t(const sp<android::EventThreadConnection> &));
     MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
-    MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
+    MOCK_METHOD2(requestNextVsync, void(const sp<android::EventThreadConnection> &, bool));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index dc8d606..e22d3e8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -30,11 +30,12 @@
     ~MessageQueue() override;
 
     MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
-    MOCK_METHOD1(setEventThread, void(android::EventThread*));
-    MOCK_METHOD1(setEventConnection, void(const sp<android::EventThreadConnection>& connection));
+    MOCK_METHOD2(setEventThread, void(android::EventThread*, ResyncCallback));
+    MOCK_METHOD1(setEventConnection, void(const sp<EventThreadConnection>& connection));
     MOCK_METHOD0(waitMessage, void());
     MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
     MOCK_METHOD0(invalidate, void());
+    MOCK_METHOD0(invalidateForHWC, void());
     MOCK_METHOD0(refresh, void());
 };
 
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 7a7e437..ba7d7f9 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -28,7 +28,6 @@
 cc_library_static {
     name: "libbufferhubd",
     srcs: [
-        "buffer_channel.cpp",
         "buffer_hub.cpp",
         "consumer_channel.cpp",
         "consumer_queue_channel.cpp",
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
deleted file mode 100644
index 695396c..0000000
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-#include <errno.h>
-#include <private/dvr/buffer_channel.h>
-#include <private/dvr/producer_channel.h>
-
-using android::pdx::BorrowedHandle;
-using android::pdx::ErrorStatus;
-using android::pdx::Message;
-using android::pdx::RemoteChannelHandle;
-using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
-
-namespace android {
-namespace dvr {
-
-BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
-                             uint32_t width, uint32_t height,
-                             uint32_t layer_count, uint32_t format,
-                             uint64_t usage, size_t user_metadata_size)
-    : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType) {
-  buffer_node_ = std::make_shared<BufferNode>(
-      width, height, layer_count, format, usage, user_metadata_size);
-  if (!buffer_node_->IsValid()) {
-    ALOGE("BufferChannel::BufferChannel: Failed to create BufferNode.");
-    return;
-  }
-  client_state_mask_ = buffer_node_->AddNewActiveClientsBitToMask();
-}
-
-BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
-                             int channel_id,
-                             std::shared_ptr<BufferNode> buffer_node)
-    : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
-      buffer_node_(buffer_node) {
-  client_state_mask_ = buffer_node_->AddNewActiveClientsBitToMask();
-  if (client_state_mask_ == 0U) {
-    ALOGE("BufferChannel::BufferChannel: %s", strerror(errno));
-    buffer_node_ = nullptr;
-  }
-}
-
-BufferChannel::~BufferChannel() {
-  ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
-           channel_id(), buffer_id());
-  if (client_state_mask_ != 0U) {
-    buffer_node_->RemoveClientsBitFromMask(client_state_mask_);
-  }
-  Hangup();
-}
-
-BufferHubChannel::BufferInfo BufferChannel::GetBufferInfo() const {
-  return BufferInfo(
-      buffer_id(), /*consumer_count=*/0, buffer_node_->buffer_desc().width,
-      buffer_node_->buffer_desc().height, buffer_node_->buffer_desc().layers,
-      buffer_node_->buffer_desc().format, buffer_node_->buffer_desc().usage,
-      /*state=*/0, /*signaled_mask=*/0, /*index=*/0);
-}
-
-void BufferChannel::HandleImpulse(Message& /*message*/) {
-  ATRACE_NAME("BufferChannel::HandleImpulse");
-}
-
-bool BufferChannel::HandleMessage(Message& message) {
-  ATRACE_NAME("BufferChannel::HandleMessage");
-  switch (message.GetOp()) {
-    case DetachedBufferRPC::Import::Opcode:
-      DispatchRemoteMethod<DetachedBufferRPC::Import>(
-          *this, &BufferChannel::OnImport, message);
-      return true;
-
-    case DetachedBufferRPC::Duplicate::Opcode:
-      DispatchRemoteMethod<DetachedBufferRPC::Duplicate>(
-          *this, &BufferChannel::OnDuplicate, message);
-      return true;
-
-    default:
-      return false;
-  }
-}
-
-Status<BufferTraits<BorrowedHandle>> BufferChannel::OnImport(
-    Message& /*message*/) {
-  ATRACE_NAME("BufferChannel::OnImport");
-  ALOGD_IF(TRACE, "BufferChannel::OnImport: buffer=%d.", buffer_id());
-
-  BorrowedHandle ashmem_handle =
-      BorrowedHandle(buffer_node_->metadata().ashmem_fd().get());
-
-  // TODO(b/112057680) Move away from the GraphicBuffer-based IonBuffer.
-  return BufferTraits<BorrowedHandle>{
-      /*buffer_handle=*/buffer_node_->buffer_handle(),
-      /*metadata_handle=*/ashmem_handle,
-      /*id=*/buffer_id(),
-      /*client_state_mask=*/client_state_mask_,
-      /*metadata_size=*/buffer_node_->metadata().metadata_size(),
-      /*width=*/buffer_node_->buffer_desc().width,
-      /*height=*/buffer_node_->buffer_desc().height,
-      /*layer_count=*/buffer_node_->buffer_desc().layers,
-      /*format=*/buffer_node_->buffer_desc().format,
-      /*usage=*/buffer_node_->buffer_desc().usage,
-      /*stride=*/buffer_node_->buffer_desc().stride,
-      /*acquire_fence_fd=*/BorrowedHandle{},
-      /*released_fence_fd=*/BorrowedHandle{}};
-}
-
-Status<RemoteChannelHandle> BufferChannel::OnDuplicate(Message& message) {
-  ATRACE_NAME("BufferChannel::OnDuplicate");
-  ALOGD_IF(TRACE, "BufferChannel::OnDuplicate: buffer=%d.", buffer_id());
-
-  int channel_id;
-  auto status = message.PushChannel(0, nullptr, &channel_id);
-  if (!status.ok()) {
-    ALOGE("BufferChannel::OnDuplicate: Failed to push buffer channel: %s",
-          status.GetErrorMessage().c_str());
-    return ErrorStatus(ENOMEM);
-  }
-
-  auto channel = std::shared_ptr<BufferChannel>(
-      new BufferChannel(service(), buffer_id(), channel_id, buffer_node_));
-  if (!channel->IsValid()) {
-    ALOGE("BufferChannel::OnDuplicate: Invalid buffer. %s", strerror(errno));
-    return ErrorStatus(EINVAL);
-  }
-
-  const auto channel_status =
-      service()->SetChannel(channel_id, std::move(channel));
-  if (!channel_status) {
-    // Technically, this should never fail, as we just pushed the channel. Note
-    // that LOG_FATAL will be stripped out in non-debug build.
-    LOG_FATAL(
-        "BufferChannel::OnDuplicate: Failed to set new buffer channel: %s.",
-        channel_status.GetErrorMessage().c_str());
-  }
-
-  return status;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index f50d292..6409265 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -10,7 +10,6 @@
 #include <log/log.h>
 #include <pdx/default_transport/service_endpoint.h>
 #include <private/dvr/bufferhub_rpc.h>
-#include <private/dvr/buffer_channel.h>
 #include <private/dvr/buffer_hub.h>
 #include <private/dvr/consumer_channel.h>
 #include <private/dvr/producer_channel.h>
@@ -242,11 +241,6 @@
           *this, &BufferHubService::OnCreateBuffer, message);
       return {};
 
-    case DetachedBufferRPC::Create::Opcode:
-      DispatchRemoteMethod<DetachedBufferRPC::Create>(
-          *this, &BufferHubService::OnCreateDetachedBuffer, message);
-      return {};
-
     case BufferHubRPC::CreateProducerQueue::Opcode:
       DispatchRemoteMethod<BufferHubRPC::CreateProducerQueue>(
           *this, &BufferHubService::OnCreateProducerQueue, message);
@@ -288,43 +282,6 @@
   }
 }
 
-pdx::Status<void> BufferHubService::OnCreateDetachedBuffer(
-    pdx::Message& message, uint32_t width, uint32_t height,
-    uint32_t layer_count, uint32_t format, uint64_t usage,
-    size_t user_metadata_size) {
-  // Use the producer channel id as the global buffer id.
-  const int buffer_id = message.GetChannelId();
-  ALOGD_IF(TRACE,
-           "BufferHubService::OnCreateDetachedBuffer: buffer_id=%d width=%u "
-           "height=%u layer_count=%u format=%u usage=%" PRIx64
-           " user_metadata_size=%zu",
-           buffer_id, width, height, layer_count, format, usage,
-           user_metadata_size);
-
-  // See if this channel is already attached to a buffer.
-  if (const auto channel = message.GetChannel<BufferHubChannel>()) {
-    ALOGE(
-        "BufferHubService::OnCreateDetachedBuffer: Buffer already created: "
-        "buffer=%d",
-        buffer_id);
-    return ErrorStatus(EALREADY);
-  }
-
-  std::unique_ptr<BufferChannel> channel =
-      BufferChannel::Create(this, buffer_id, width, height, layer_count, format,
-                            usage, user_metadata_size);
-  if (!channel) {
-    ALOGE(
-        "BufferHubService::OnCreateDetachedBuffer: Failed to allocate buffer, "
-        "buffer=%d.",
-        buffer_id);
-    return ErrorStatus(ENOMEM);
-  }
-
-  message.SetChannel(std::move(channel));
-  return {};
-}
-
 Status<QueueInfo> BufferHubService::OnCreateProducerQueue(
     pdx::Message& message, const ProducerQueueConfig& producer_config,
     const UsagePolicy& usage_policy) {
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
deleted file mode 100644
index 9888db6..0000000
--- a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
-#define ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
-
-#include <pdx/channel_handle.h>
-#include <pdx/file_handle.h>
-#include <private/dvr/buffer_hub.h>
-#include <private/dvr/buffer_hub_defs.h>
-#include <private/dvr/buffer_node.h>
-
-namespace android {
-namespace dvr {
-
-class BufferChannel : public BufferHubChannel {
- public:
-  ~BufferChannel() override;
-
-  template <typename... Args>
-  static std::unique_ptr<BufferChannel> Create(Args&&... args) {
-    auto buffer = std::unique_ptr<BufferChannel>(
-        new BufferChannel(std::forward<Args>(args)...));
-    return buffer->IsValid() ? std::move(buffer) : nullptr;
-  }
-
-  // Returns whether the object holds a valid graphic buffer.
-  bool IsValid() const {
-    return buffer_node_ != nullptr && buffer_node_->IsValid();
-  }
-
-  // Captures buffer info for use by BufferHubService::DumpState().
-  BufferInfo GetBufferInfo() const override;
-
-  bool HandleMessage(pdx::Message& message) override;
-  void HandleImpulse(pdx::Message& message) override;
-
- private:
-
-  // Allocates a new detached buffer.
-  BufferChannel(BufferHubService* service, int buffer_id, uint32_t width,
-                uint32_t height, uint32_t layer_count, uint32_t format,
-                uint64_t usage, size_t user_metadata_size);
-
-  // Creates a detached buffer from an existing BufferNode. This method is used
-  // in OnDuplicate method.
-  BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
-                std::shared_ptr<BufferNode> buffer_node);
-
-  pdx::Status<BufferTraits<pdx::BorrowedHandle>> OnImport(
-      pdx::Message& message);
-  pdx::Status<pdx::RemoteChannelHandle> OnDuplicate(pdx::Message& message);
-
-  // The concrete implementation of the Buffer object.
-  std::shared_ptr<BufferNode> buffer_node_ = nullptr;
-
-  // The state bit of this buffer.
-  uint32_t client_state_mask_ = 0U;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub.h
index 01520fc..909d69b 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub.h
@@ -144,11 +144,6 @@
   pdx::Status<void> OnCreateBuffer(pdx::Message& message, uint32_t width,
                                    uint32_t height, uint32_t format,
                                    uint64_t usage, size_t meta_size_bytes);
-  pdx::Status<void> OnCreateDetachedBuffer(pdx::Message& message,
-                                           uint32_t width, uint32_t height,
-                                           uint32_t layer_count,
-                                           uint32_t format, uint64_t usage,
-                                           size_t user_metadata_size);
   pdx::Status<QueueInfo> OnCreateProducerQueue(
       pdx::Message& message, const ProducerQueueConfig& producer_config,
       const UsagePolicy& usage_policy);
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 409bce9..895dee0 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -7,7 +7,6 @@
 #include <thread>
 
 #include <log/log.h>
-#include <private/dvr/buffer_channel.h>
 #include <private/dvr/bufferhub_rpc.h>
 #include <private/dvr/consumer_channel.h>
 #include <private/dvr/producer_channel.h>
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 258b45b..d9df204 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -15,6 +15,7 @@
     "android.frameworks.vr.composer@1.0",
     "android.hardware.graphics.composer@2.1",
     "android.hardware.graphics.mapper@2.0",
+    "android.hardware.graphics.mapper@3.0",
     "libbase",
     "libbufferhubqueue",
     "libbinder",
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 009b257..ba4cf00 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -139,12 +139,12 @@
         auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
         if (app_namespace &&
             !android::base::StartsWith(path_, kSystemLayerLibraryDir)) {
-            std::string error_msg;
-            dlhandle_ = OpenNativeLibrary(
+            char* error_msg = nullptr;
+            dlhandle_ = OpenNativeLibraryInNamespace(
                 app_namespace, path_.c_str(), &native_bridge_, &error_msg);
             if (!dlhandle_) {
-                ALOGE("failed to load layer library '%s': %s", path_.c_str(),
-                      error_msg.c_str());
+                ALOGE("failed to load layer library '%s': %s", path_.c_str(), error_msg);
+                android::NativeLoaderFreeErrorMessage(error_msg);
                 refcount_ = 0;
                 return false;
             }
@@ -165,9 +165,10 @@
     std::lock_guard<std::mutex> lock(mutex_);
     if (--refcount_ == 0) {
         ALOGV("closing layer library '%s'", path_.c_str());
-        std::string error_msg;
+        char* error_msg = nullptr;
         if (!android::CloseNativeLibrary(dlhandle_, native_bridge_, &error_msg)) {
-            ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg.c_str());
+            ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg);
+            android::NativeLoaderFreeErrorMessage(error_msg);
             refcount_++;
         } else {
            dlhandle_ = nullptr;