Merge "Add dependency on libdl_android"
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 37ff442..347856d 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -61,7 +61,6 @@
     // Default mode.
     const int BUGREPORT_MODE_DEFAULT = 6;
 
-    // TODO(b/111441001): Should the args be for the consuming application rather than triggering?
     /*
      * Starts a bugreport in the background.
      *
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 738c20f..2cc1b32 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -34,6 +34,7 @@
 #include <unistd.h>
 
 #include <chrono>
+#include <fstream>
 #include <functional>
 #include <future>
 #include <memory>
@@ -194,6 +195,15 @@
     return true;
 }
 
+static bool IsFileEmpty(const std::string& file_path) {
+    std::ifstream file(file_path, std::ios::binary | std::ios::ate);
+    if(file.bad()) {
+        MYLOGE("Cannot open file: %s\n", file_path.c_str());
+        return true;
+    }
+    return file.tellg() <= 0;
+}
+
 }  // namespace
 }  // namespace os
 }  // namespace android
@@ -1583,6 +1593,9 @@
 
     RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
                SEC_TO_MSEC(10));
+    RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
+    RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
     RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
                SEC_TO_MSEC(10));
     RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
@@ -2146,7 +2159,7 @@
              "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
         };
         // clang-format on
-        if (ds.options_->do_fb) {
+        if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
             am_args.push_back("--es");
             am_args.push_back("android.intent.extra.SCREENSHOT");
             am_args.push_back(ds.screenshot_path_);
@@ -2222,13 +2235,13 @@
             break;
         case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
             options->telephony_only = true;
-            options->do_fb = true;
+            options->do_fb = false;
             options->do_broadcast = true;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_WIFI:
             options->wifi_only = true;
             options->do_zip_file = true;
-            options->do_fb = true;
+            options->do_fb = false;
             options->do_broadcast = true;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
@@ -2732,8 +2745,8 @@
     if (ics != nullptr) {
         MYLOGD("Checking user consent via incidentcompanion service\n");
         android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
-            calling_uid, calling_package, 0x1 /* FLAG_CONFIRMATION_DIALOG */,
-            consent_callback_.get());
+            calling_uid, calling_package, String16(), String16(),
+            0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
     } else {
         MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
     }
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index eb73d41..e6a7735 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -373,7 +373,7 @@
 
     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
     EXPECT_TRUE(options_.do_add_date);
-    EXPECT_TRUE(options_.do_fb);
+    EXPECT_FALSE(options_.do_fb);
     EXPECT_TRUE(options_.do_broadcast);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.telephony_only);
@@ -404,7 +404,7 @@
 
     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
     EXPECT_TRUE(options_.do_add_date);
-    EXPECT_TRUE(options_.do_fb);
+    EXPECT_FALSE(options_.do_fb);
     EXPECT_TRUE(options_.do_broadcast);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.wifi_only);
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index b60bbc0..d66066e 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -146,9 +146,11 @@
     ],
     shared_libs: [
         "libbase",
+        "libbinder",
         "liblog",
         "libprotobuf-cpp-full",
         "libselinux",
+        "libutils",
         "libziparchive",
     ],
     static_libs: [
@@ -157,6 +159,7 @@
         "lib_apex_manifest_proto",
         "libavb",
         "libdm",
+        "libvold_binder",
     ],
 }
 
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 2efcf11..c730ab9 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -171,7 +171,7 @@
 }
 
 binder::Status checkArgumentPackageName(const std::string& packageName) {
-    if (is_valid_package_name(packageName.c_str())) {
+    if (is_valid_package_name(packageName)) {
         return ok();
     } else {
         return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
@@ -1648,7 +1648,8 @@
 
     ATRACE_BEGIN("obb");
     for (const auto& packageName : packageNames) {
-        auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
+        auto obbCodePath = create_data_media_package_path(uuid_, userId,
+                "obb", packageName.c_str());
         calculate_tree_size(obbCodePath, &extStats.codeSize);
     }
     ATRACE_END();
@@ -1982,7 +1983,8 @@
         ATRACE_END();
 
         ATRACE_BEGIN("obb");
-        auto obbPath = create_data_media_obb_path(uuid_, "");
+        auto obbPath = StringPrintf("%s/Android/obb",
+                create_data_media_path(uuid_, userId).c_str());
         calculate_tree_size(obbPath, &obbSize);
         ATRACE_END();
     }
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 72571cf..a5cc0df 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -58,6 +58,7 @@
 using android::base::EndsWith;
 using android::base::GetBoolProperty;
 using android::base::GetProperty;
+using android::base::ReadFdToString;
 using android::base::ReadFully;
 using android::base::StringPrintf;
 using android::base::WriteFully;
@@ -319,6 +320,7 @@
                bool background_job_compile,
                int profile_fd,
                const char* class_loader_context,
+               const std::string& class_loader_context_fds,
                int target_sdk_version,
                bool enable_hidden_api_checks,
                bool generate_compact_dex,
@@ -423,9 +425,14 @@
             target_sdk_version_arg = StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
         }
         std::string class_loader_context_arg;
+        std::string class_loader_context_fds_arg;
         if (class_loader_context != nullptr) {
             class_loader_context_arg = StringPrintf("--class-loader-context=%s",
                                                     class_loader_context);
+            if (!class_loader_context_fds.empty()) {
+                class_loader_context_fds_arg = StringPrintf("--class-loader-context-fds=%s",
+                                                            class_loader_context_fds.c_str());
+            }
         }
 
         if (swap_fd >= 0) {
@@ -518,6 +525,7 @@
         AddArg(profile_arg);
         AddArg(base_dir);
         AddArg(class_loader_context_arg);
+        AddArg(class_loader_context_fds_arg);
         if (generate_minidebug_info) {
             AddArg(kMinidebugDex2oatFlag);
         }
@@ -1514,14 +1522,15 @@
 class RunDexoptAnalyzer : public ExecVHelper {
  public:
     RunDexoptAnalyzer(const std::string& dex_file,
-                    int vdex_fd,
-                    int oat_fd,
-                    int zip_fd,
-                    const std::string& instruction_set,
-                    const std::string& compiler_filter,
-                    bool profile_was_updated,
-                    bool downgrade,
-                    const char* class_loader_context) {
+                      int vdex_fd,
+                      int oat_fd,
+                      int zip_fd,
+                      const std::string& instruction_set,
+                      const std::string& compiler_filter,
+                      bool profile_was_updated,
+                      bool downgrade,
+                      const char* class_loader_context,
+                      const std::string& class_loader_context_fds) {
         CHECK_GE(zip_fd, 0);
 
         // We always run the analyzer in the background job.
@@ -1540,6 +1549,10 @@
         if (class_loader_context != nullptr) {
             class_loader_context_arg += class_loader_context;
         }
+        std::string class_loader_context_fds_arg = "--class-loader-context-fds=";
+        if (!class_loader_context_fds.empty()) {
+            class_loader_context_fds_arg += class_loader_context_fds;
+        }
 
         // program name, dex file, isa, filter
         AddArg(dex_file_arg);
@@ -1551,7 +1564,7 @@
         if (vdex_fd >= 0) {
             AddArg(vdex_fd_arg);
         }
-        AddArg(zip_fd_arg.c_str());
+        AddArg(zip_fd_arg);
         if (profile_was_updated) {
             AddArg(assume_profile_changed);
         }
@@ -1559,11 +1572,28 @@
             AddArg(downgrade_flag);
         }
         if (class_loader_context != nullptr) {
-            AddArg(class_loader_context_arg.c_str());
+            AddArg(class_loader_context_arg);
+            if (!class_loader_context_fds.empty()) {
+                AddArg(class_loader_context_fds_arg);
+            }
         }
 
         PrepareArgs(dexoptanalyzer_bin);
     }
+
+    // Dexoptanalyzer mode which flattens the given class loader context and
+    // prints a list of its dex files in that flattened order.
+    RunDexoptAnalyzer(const char* class_loader_context) {
+        CHECK(class_loader_context != nullptr);
+
+        // We always run the analyzer in the background job.
+        const char* dexoptanalyzer_bin = select_execution_binary(
+             kDexoptanalyzerPath, kDexoptanalyzerDebugPath, /*background_job_compile=*/ true);
+
+        AddArg("--flatten-class-loader-context");
+        AddArg(std::string("--class-loader-context=") + class_loader_context);
+        PrepareArgs(dexoptanalyzer_bin);
+    }
 };
 
 // Prepares the oat dir for the secondary dex files.
@@ -1743,6 +1773,95 @@
     return true;
 }
 
+static bool get_class_loader_context_dex_paths(const char* class_loader_context, int uid,
+        /* out */ std::vector<std::string>* context_dex_paths) {
+    if (class_loader_context == nullptr) {
+      return true;
+    }
+
+    LOG(DEBUG) << "Getting dex paths for context " << class_loader_context;
+
+    // Pipe to get the hash result back from our child process.
+    unique_fd pipe_read, pipe_write;
+    if (!Pipe(&pipe_read, &pipe_write)) {
+        PLOG(ERROR) << "Failed to create pipe";
+        return false;
+    }
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        // child -- drop privileges before continuing.
+        drop_capabilities(uid);
+
+        // Route stdout to `pipe_write`
+        while ((dup2(pipe_write, STDOUT_FILENO) == -1) && (errno == EINTR)) {}
+        pipe_write.reset();
+        pipe_read.reset();
+
+        RunDexoptAnalyzer run_dexopt_analyzer(class_loader_context);
+        run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
+    }
+
+    /* parent */
+    pipe_write.reset();
+
+    std::string str_dex_paths;
+    if (!ReadFdToString(pipe_read, &str_dex_paths)) {
+        PLOG(ERROR) << "Failed to read from pipe";
+        return false;
+    }
+    pipe_read.reset();
+
+    int return_code = wait_child(pid);
+    if (!WIFEXITED(return_code)) {
+        PLOG(ERROR) << "Error waiting for child dexoptanalyzer process";
+        return false;
+    }
+
+    constexpr int kFlattenClassLoaderContextSuccess = 50;
+    return_code = WEXITSTATUS(return_code);
+    if (return_code != kFlattenClassLoaderContextSuccess) {
+        LOG(ERROR) << "Dexoptanalyzer could not flatten class loader context, code=" << return_code;
+        return false;
+    }
+
+    if (!str_dex_paths.empty()) {
+        *context_dex_paths = android::base::Split(str_dex_paths, ":");
+    }
+    return true;
+}
+
+static int open_dex_paths(const std::vector<std::string>& dex_paths,
+        /* out */ std::vector<unique_fd>* zip_fds, /* out */ std::string* error_msg) {
+    for (const std::string& dex_path : dex_paths) {
+        zip_fds->emplace_back(open(dex_path.c_str(), O_RDONLY));
+        if (zip_fds->back().get() < 0) {
+            *error_msg = StringPrintf(
+                    "installd cannot open '%s' for input during dexopt", dex_path.c_str());
+            if (errno == ENOENT) {
+                return kSecondaryDexDexoptAnalyzerSkippedNoFile;
+            } else {
+                return kSecondaryDexDexoptAnalyzerSkippedOpenZip;
+            }
+        }
+    }
+    return 0;
+}
+
+static std::string join_fds(const std::vector<unique_fd>& fds) {
+    std::stringstream ss;
+    bool is_first = true;
+    for (const unique_fd& fd : fds) {
+        if (is_first) {
+            is_first = false;
+        } else {
+            ss << ":";
+        }
+        ss << fd.get();
+    }
+    return ss.str();
+}
+
 // Processes the dex_path as a secondary dex files and return true if the path dex file should
 // be compiled. Returns false for errors (logged) or true if the secondary dex path was process
 // successfully.
@@ -1754,7 +1873,7 @@
         int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
         const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
         std::string* oat_dir_out, bool downgrade, const char* class_loader_context,
-        /* out */ std::string* error_msg) {
+        const std::vector<std::string>& context_dex_paths, /* out */ std::string* error_msg) {
     LOG(DEBUG) << "Processing secondary dex path " << dex_path;
     int storage_flag;
     if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) {
@@ -1794,6 +1913,13 @@
             }
         }
 
+        // Open class loader context dex files.
+        std::vector<unique_fd> context_zip_fds;
+        int open_dex_paths_rc = open_dex_paths(context_dex_paths, &context_zip_fds, error_msg);
+        if (open_dex_paths_rc != 0) {
+            _exit(open_dex_paths_rc);
+        }
+
         // Prepare the oat directories.
         if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set)) {
             _exit(kSecondaryDexDexoptAnalyzerSkippedPrepareDir);
@@ -1825,7 +1951,8 @@
                                               instruction_set,
                                               compiler_filter, profile_was_updated,
                                               downgrade,
-                                              class_loader_context);
+                                              class_loader_context,
+                                              join_fds(context_zip_fds));
         run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
     }
 
@@ -1913,10 +2040,16 @@
 
     // Check if we're dealing with a secondary dex file and if we need to compile it.
     std::string oat_dir_str;
+    std::vector<std::string> context_dex_paths;
     if (is_secondary_dex) {
+        if (!get_class_loader_context_dex_paths(class_loader_context, uid, &context_dex_paths)) {
+            *error_msg = "Failed acquiring context dex paths";
+            return -1;  // We had an error, logged in the process method.
+        }
+
         if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
                 instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
-                downgrade, class_loader_context, error_msg)) {
+                downgrade, class_loader_context, context_dex_paths, error_msg)) {
             oat_dir = oat_dir_str.c_str();
             if (dexopt_needed == NO_DEXOPT_NEEDED) {
                 return 0;  // Nothing to do, report success.
@@ -1928,7 +2061,7 @@
             return -1;  // We had an error, logged in the process method.
         }
     } else {
-        // Currently these flags are only use for secondary dex files.
+        // Currently these flags are only used for secondary dex files.
         // Verify that they are not set for primary apks.
         CHECK((dexopt_flags & DEXOPT_STORAGE_CE) == 0);
         CHECK((dexopt_flags & DEXOPT_STORAGE_DE) == 0);
@@ -1942,6 +2075,13 @@
         return -1;
     }
 
+    // Open class loader context dex files.
+    std::vector<unique_fd> context_input_fds;
+    if (open_dex_paths(context_dex_paths, &context_input_fds, error_msg) != 0) {
+        LOG(ERROR) << *error_msg;
+        return -1;
+    }
+
     // Create the output OAT file.
     char out_oat_path[PKG_PATH_MAX];
     Dex2oatFileWrapper out_oat_fd = open_oat_out_file(dex_path, oat_dir, is_public, uid,
@@ -2010,6 +2150,7 @@
                       background_job_compile,
                       reference_profile_fd.get(),
                       class_loader_context,
+                      join_fds(context_input_fds),
                       target_sdk_version,
                       enable_hidden_api_checks,
                       generate_compact_dex,
@@ -2118,7 +2259,7 @@
         drop_capabilities(uid);
 
         const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
-        if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
+        if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr,
                 uid, storage_flag)) {
             LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
             _exit(kReconcileSecondaryDexValidationError);
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 0fdc9d6..2e2cc18 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -25,6 +25,7 @@
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
+#include <libdm/dm.h>
 #include <selinux/android.h>
 
 #include <apexd.h>
@@ -77,6 +78,37 @@
     }
 }
 
+static void TryExtraMount(const char* name, const char* slot, const char* target) {
+    std::string partition_name = StringPrintf("%s%s", name, slot);
+
+    // See whether update_engine mounted a logical partition.
+    {
+        auto& dm = dm::DeviceMapper::Instance();
+        if (dm.GetState(partition_name) != dm::DmDeviceState::INVALID) {
+            std::string path;
+            if (dm.GetDmDevicePathByName(partition_name, &path)) {
+                int mount_result = mount(path.c_str(),
+                                         target,
+                                         "ext4",
+                                         MS_RDONLY,
+                                         /* data */ nullptr);
+                if (mount_result == 0) {
+                    return;
+                }
+            }
+        }
+    }
+
+    // Fall back and attempt a direct mount.
+    std::string block_device = StringPrintf("/dev/block/by-name/%s", partition_name.c_str());
+    int mount_result = mount(block_device.c_str(),
+                             target,
+                             "ext4",
+                             MS_RDONLY,
+                             /* data */ nullptr);
+    UNUSED(mount_result);
+}
+
 // Entry for otapreopt_chroot. Expected parameters are:
 //   [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
 // The file descriptor denoted by status-fd will be closed. The rest of the parameters will
@@ -137,29 +169,11 @@
         LOG(ERROR) << "Target slot suffix not legal: " << arg[2];
         exit(207);
     }
-    {
-      std::string vendor_partition = StringPrintf("/dev/block/by-name/vendor%s",
-                                                  arg[2]);
-      int vendor_result = mount(vendor_partition.c_str(),
-                                "/postinstall/vendor",
-                                "ext4",
-                                MS_RDONLY,
-                                /* data */ nullptr);
-      UNUSED(vendor_result);
-    }
+    TryExtraMount("vendor", arg[2], "/postinstall/vendor");
 
     // Try to mount the product partition. update_engine doesn't do this for us, but we
     // want it for product APKs. Same notes as vendor above.
-    {
-      std::string product_partition = StringPrintf("/dev/block/by-name/product%s",
-                                                   arg[2]);
-      int product_result = mount(product_partition.c_str(),
-                                 "/postinstall/product",
-                                 "ext4",
-                                 MS_RDONLY,
-                                 /* data */ nullptr);
-      UNUSED(product_result);
-    }
+    TryExtraMount("product", arg[2], "/postinstall/product");
 
     // Setup APEX mount point and its security context.
     static constexpr const char* kPostinstallApexDir = "/postinstall/apex";
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 1ed49a0..aa79fdc 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -15,6 +15,7 @@
         "libinstalld",
         "liblog",
     ],
+    test_config: "installd_utils_test.xml",
 }
 
 cc_test {
@@ -39,6 +40,7 @@
         "liblog",
         "liblogwrap",
     ],
+    test_config: "installd_cache_test.xml",
 }
 
 cc_test {
@@ -63,6 +65,7 @@
         "liblog",
         "liblogwrap",
     ],
+    test_config: "installd_service_test.xml",
 }
 
 cc_test {
@@ -87,6 +90,7 @@
         "liblog",
         "liblogwrap",
     ],
+    test_config: "installd_dexopt_test.xml",
 }
 
 cc_test {
diff --git a/cmds/installd/tests/installd_cache_test.xml b/cmds/installd/tests/installd_cache_test.xml
new file mode 100644
index 0000000..97af514
--- /dev/null
+++ b/cmds/installd/tests/installd_cache_test.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+           root support. -->
+<configuration description="Runs installd_cache_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="installd_cache_test->/data/local/tmp/installd_cache_test" />
+    </target_preparer>
+
+    <!-- The test requires root for file access. -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="installd_cache_test" />
+    </test>
+</configuration>
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 71b710b..fa2b0d9 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -327,16 +327,21 @@
 
     void CompileSecondaryDex(const std::string& path, int32_t dex_storage_flag,
             bool should_binder_call_succeed, bool should_dex_be_compiled = true,
-            /*out */ binder::Status* binder_result = nullptr, int32_t uid = -1) {
+            /*out */ binder::Status* binder_result = nullptr, int32_t uid = -1,
+            const char* class_loader_context = nullptr) {
         if (uid == -1) {
             uid = kTestAppUid;
         }
+        if (class_loader_context == nullptr) {
+            class_loader_context = "&";
+        }
         std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
         int32_t dexopt_needed = 0;  // does not matter;
         std::unique_ptr<std::string> out_path = nullptr;  // does not matter
         int32_t dex_flags = DEXOPT_SECONDARY_DEX | dex_storage_flag;
         std::string compiler_filter = "speed-profile";
-        std::unique_ptr<std::string> class_loader_context_ptr(new std::string("&"));
+        std::unique_ptr<std::string> class_loader_context_ptr(
+                new std::string(class_loader_context));
         std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
         bool downgrade = false;
         int32_t target_sdk_version = 0;  // default
@@ -555,12 +560,26 @@
         /*binder_ok*/ true, /*compile_ok*/ true);
 }
 
+TEST_F(DexoptTest, DexoptSecondaryCeWithContext) {
+    LOG(INFO) << "DexoptSecondaryCeWithContext";
+    std::string class_loader_context = "PCL[" + secondary_dex_ce_ + "]";
+    CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+        /*binder_ok*/ true, /*compile_ok*/ true, nullptr, -1, class_loader_context.c_str());
+}
+
 TEST_F(DexoptTest, DexoptSecondaryDe) {
     LOG(INFO) << "DexoptSecondaryDe";
     CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
         /*binder_ok*/ true, /*compile_ok*/ true);
 }
 
+TEST_F(DexoptTest, DexoptSecondaryDeWithContext) {
+    LOG(INFO) << "DexoptSecondaryDeWithContext";
+    std::string class_loader_context = "PCL[" + secondary_dex_de_ + "]";
+    CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
+        /*binder_ok*/ true, /*compile_ok*/ true, nullptr, -1, class_loader_context.c_str());
+}
+
 TEST_F(DexoptTest, DexoptSecondaryDoesNotExist) {
     LOG(INFO) << "DexoptSecondaryDoesNotExist";
     // If the file validates but does not exist we do not treat it as an error.
@@ -576,7 +595,7 @@
     CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_DE,
         /*binder_ok*/ false,  /*compile_ok*/ false, &status);
     EXPECT_STREQ(status.toString8().c_str(),
-                 "Status(-8): '-1: Dexoptanalyzer path validation failed'");
+                 "Status(-8, EX_SERVICE_SPECIFIC): '-1: Dexoptanalyzer path validation failed'");
 }
 
 TEST_F(DexoptTest, DexoptSecondaryAppOwnershipValidationError) {
@@ -585,7 +604,7 @@
     CompileSecondaryDex("/data/data/random.app/secondary.jar", DEXOPT_STORAGE_CE,
         /*binder_ok*/ false,  /*compile_ok*/ false, &status);
     EXPECT_STREQ(status.toString8().c_str(),
-                 "Status(-8): '-1: Dexoptanalyzer path validation failed'");
+                 "Status(-8, EX_SERVICE_SPECIFIC): '-1: Dexoptanalyzer path validation failed'");
 }
 
 TEST_F(DexoptTest, DexoptSecondaryAcessViaDifferentUidError) {
@@ -593,7 +612,8 @@
     binder::Status status;
     CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
         /*binder_ok*/ false,  /*compile_ok*/ false, &status, kSystemUid);
-    EXPECT_STREQ(status.toString8().c_str(), "Status(-8): '-1: Dexoptanalyzer open zip failed'");
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8, EX_SERVICE_SPECIFIC): '-1: Dexoptanalyzer open zip failed'");
 }
 
 TEST_F(DexoptTest, DexoptPrimaryPublic) {
@@ -615,7 +635,7 @@
                           DEX2OAT_FROM_SCRATCH,
                           &status);
     EXPECT_STREQ(status.toString8().c_str(),
-                 "Status(-8): \'256: Dex2oat invocation for "
+                 "Status(-8, EX_SERVICE_SPECIFIC): \'256: Dex2oat invocation for "
                  "/data/app/com.installd.test.dexopt/base.jar failed: unspecified dex2oat error'");
 }
 
@@ -916,8 +936,7 @@
   protected:
     void TransitionToSystemServer() {
         ASSERT_TRUE(DropCapabilities(kSystemUid, kSystemGid));
-        int32_t res = selinux_android_setcontext(
-                kSystemUid, true, se_info_.c_str(), "system_server");
+        int32_t res = selinux_android_setcon("u:r:system_server:s0");
         ASSERT_EQ(0, res) << "Failed to setcon " << strerror(errno);
     }
 
diff --git a/cmds/installd/tests/installd_dexopt_test.xml b/cmds/installd/tests/installd_dexopt_test.xml
new file mode 100644
index 0000000..24526cc
--- /dev/null
+++ b/cmds/installd/tests/installd_dexopt_test.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+           root support. -->
+<configuration description="Runs installd_dexopt_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="installd_dexopt_test->/data/local/tmp/installd_dexopt_test" />
+    </target_preparer>
+
+    <!-- The test runs as root to prepare the temporary directory, make selinux adjustments
+         and so on. -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="installd_dexopt_test" />
+    </test>
+</configuration>
diff --git a/cmds/installd/tests/installd_service_test.xml b/cmds/installd/tests/installd_service_test.xml
new file mode 100644
index 0000000..b838f4f
--- /dev/null
+++ b/cmds/installd/tests/installd_service_test.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+           root support. -->
+<configuration description="Runs installd_service_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="installd_service_test->/data/local/tmp/installd_service_test" />
+    </target_preparer>
+
+    <!-- The test requires root for file access. -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="installd_service_test" />
+    </test>
+</configuration>
diff --git a/cmds/installd/tests/installd_utils_test.xml b/cmds/installd/tests/installd_utils_test.xml
new file mode 100644
index 0000000..92aba50
--- /dev/null
+++ b/cmds/installd/tests/installd_utils_test.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+           root support. -->
+<configuration description="Runs installd_utils_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="installd_utils_test->/data/local/tmp/installd_utils_test" />
+    </target_preparer>
+
+    <!-- The test requires root for file access (rollback paths). -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="installd_utils_test" />
+    </test>
+</configuration>
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index da097db..4eb1df0 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -244,10 +244,6 @@
     return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid);
 }
 
-std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name) {
-    return StringPrintf("%s/media/obb/%s", create_data_path(volume_uuid).c_str(), package_name);
-}
-
 std::string create_data_media_package_path(const char* volume_uuid, userid_t userid,
         const char* data_type, const char* package_name) {
     return StringPrintf("%s/Android/%s/%s", create_data_media_path(volume_uuid, userid).c_str(),
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 955d524..6a42026 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -75,7 +75,6 @@
         userid_t user, int32_t snapshot_id, const char* package_name);
 
 std::string create_data_media_path(const char* volume_uuid, userid_t userid);
-std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name);
 std::string create_data_media_package_path(const char* volume_uuid, userid_t userid,
         const char* data_type, const char* package_name);
 
diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h
index 70be3b4..a9ccc74 100644
--- a/cmds/servicemanager/binder.h
+++ b/cmds/servicemanager/binder.h
@@ -4,10 +4,9 @@
 #ifndef _BINDER_H_
 #define _BINDER_H_
 
+#include <linux/android/binder.h>
 #include <sys/ioctl.h>
 
-#include "binder_kernel.h"
-
 struct binder_state;
 
 struct binder_io
diff --git a/cmds/servicemanager/binder_kernel.h b/cmds/servicemanager/binder_kernel.h
deleted file mode 100644
index 19fd773..0000000
--- a/cmds/servicemanager/binder_kernel.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_BINDER_KERNEL_H
-#define ANDROID_BINDER_KERNEL_H
-
-#include <linux/android/binder.h>
-
-/**
- * This file exists because the uapi kernel headers in bionic are built
- * from upstream kernel headers only, and not all of the hwbinder kernel changes
- * have made it upstream yet. Therefore, the modifications to the
- * binder header are added locally in this file.
- */
-
-enum {
-        FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000,
-};
-
-#define BINDER_SET_CONTEXT_MGR_EXT      _IOW('b', 13, struct flat_binder_object)
-
-struct binder_transaction_data_secctx {
-        struct binder_transaction_data transaction_data;
-        binder_uintptr_t secctx;
-};
-
-enum {
-        BR_TRANSACTION_SEC_CTX = _IOR('r', 2,
-                              struct binder_transaction_data_secctx),
-};
-
-
-#endif // ANDROID_BINDER_KERNEL_H
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index 5c1cab6..ad7791e 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -46,12 +46,6 @@
     <feature name="android.software.cant_save_state" />
     <feature name="android.software.secure_lock_screen" />
 
-    <!-- Feature to specify if the device supports adding device admins. -->
-    <feature name="android.software.device_admin" />
-
-    <!-- Feature to specify if the device support managed users. -->
-    <feature name="android.software.managed_users" />
-
     <!-- devices with GPS must include android.hardware.location.gps.xml -->
     <!-- devices with an autofocus camera and/or flash must include either
          android.hardware.camera.autofocus.xml or
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index cd12fcd..4365a3c 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -22,7 +22,6 @@
 
 #include <binder/IInterface.h>
 
-#include <utils/Vector.h>
 #include <input/InputWindow.h>
 #include <input/ISetInputWindowsListener.h>
 
@@ -36,7 +35,7 @@
 public:
     DECLARE_META_INTERFACE(InputFlinger)
 
-    virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles,
+    virtual void setInputWindows(const std::vector<InputWindowInfo>& inputHandles,
             const sp<ISetInputWindowsListener>& setInputWindowsListener) = 0;
     virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
     virtual void registerInputChannel(const sp<InputChannel>& channel) = 0;
diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h
index 71a8f20..7f04611 100644
--- a/include/input/InputApplication.h
+++ b/include/input/InputApplication.h
@@ -50,19 +50,19 @@
 class InputApplicationHandle : public RefBase {
 public:
     inline const InputApplicationInfo* getInfo() const {
-        return mInfo;
+        return &mInfo;
     }
 
     inline std::string getName() const {
-        return mInfo ? mInfo->name : "<invalid>";
+        return !mInfo.name.empty() ? mInfo.name : "<invalid>";
     }
 
     inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
-        return mInfo ? mInfo->dispatchingTimeout : defaultValue;
+        return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
     }
 
     inline sp<IBinder> getApplicationToken() const {
-        return mInfo ? mInfo->token : nullptr;
+        return mInfo.token;
     }
 
     /**
@@ -75,18 +75,11 @@
      * Returns true on success, or false if the handle is no longer valid.
      */
     virtual bool updateInfo() = 0;
-
-    /**
-     * Releases the storage used by the associated information when it is
-     * no longer needed.
-     */
-    void releaseInfo();
-
 protected:
     InputApplicationHandle();
     virtual ~InputApplicationHandle();
 
-    InputApplicationInfo* mInfo;
+    InputApplicationInfo mInfo;
 };
 
 } // namespace android
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 48ac88d..b6efc82 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -19,6 +19,7 @@
 
 #include <input/Input.h>
 #include <input/KeyCharacterMap.h>
+#include <vector>
 
 namespace android {
 
@@ -121,7 +122,7 @@
     inline void setButtonUnderPad(bool hasButton) { mHasButtonUnderPad = hasButton; }
     inline bool hasButtonUnderPad() const { return mHasButtonUnderPad; }
 
-    inline const Vector<MotionRange>& getMotionRanges() const {
+    inline const std::vector<MotionRange>& getMotionRanges() const {
         return mMotionRanges;
     }
 
@@ -139,7 +140,7 @@
     bool mHasVibrator;
     bool mHasButtonUnderPad;
 
-    Vector<MotionRange> mMotionRanges;
+    std::vector<MotionRange> mMotionRanges;
 };
 
 /* Types of input device configuration files. */
diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h
index 73815fe..26f3501 100644
--- a/include/input/KeyLayoutMap.h
+++ b/include/input/KeyLayoutMap.h
@@ -66,7 +66,7 @@
 
     status_t mapKey(int32_t scanCode, int32_t usageCode,
             int32_t* outKeyCode, uint32_t* outFlags) const;
-    status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
+    status_t findScanCodesForKey(int32_t keyCode, std::vector<int32_t>* outScanCodes) const;
     status_t findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const;
     status_t findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const;
 
diff --git a/include/input/VirtualKeyMap.h b/include/input/VirtualKeyMap.h
index 4f7cfb6..6e8e2c9 100644
--- a/include/input/VirtualKeyMap.h
+++ b/include/input/VirtualKeyMap.h
@@ -24,6 +24,7 @@
 #include <utils/KeyedVector.h>
 #include <utils/Tokenizer.h>
 #include <utils/Unicode.h>
+#include <vector>
 
 namespace android {
 
@@ -51,7 +52,7 @@
 
     static std::unique_ptr<VirtualKeyMap> load(const std::string& filename);
 
-    inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
+    inline const std::vector<VirtualKeyDefinition>& getVirtualKeys() const {
         return mVirtualKeys;
     }
 
@@ -70,7 +71,7 @@
         bool parseNextIntField(int32_t* outValue);
     };
 
-    Vector<VirtualKeyDefinition> mVirtualKeys;
+    std::vector<VirtualKeyDefinition> mVirtualKeys;
 
     VirtualKeyMap();
 };
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
new file mode 100644
index 0000000..9284acb
--- /dev/null
+++ b/libs/android_runtime_lazy/Android.bp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// libandroid_runtime_lazy is a shim library.
+// This provides very limited small set of APIs from libandroid_runtime.
+//
+// By depending on this instead of libandroid_runtime,
+// a library can be loaded without paying the cost of libandroid_runtime
+// which is quite huge. The cost will be paid when libandroid_runtime is actually used.
+//
+// For Partial-source PDK build, there is a constraint that
+// frameworks/native modules should not depend on frameworks/base.
+// This library can be used to cut down the dependency between them.
+// (e.g. libbinder_ndk)
+//
+// Some libraries which serve as LL-NDK and NDK as well may depend on this
+// instead of libandroid_runtime. When they are used by a vendor process,
+// depending on libandroid_runtime is meaningless. In this case,
+// they can depend on libandroid_runtime_lazy.
+cc_library {
+    name: "libandroid_runtime_lazy",
+    vendor_available: true,
+    double_loadable: true,
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+
+    srcs: [
+        "android_runtime_lazy.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+    ],
+
+    required: [
+        "libandroid_runtime",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    header_libs: [
+        "jni_headers",
+        "libbinder_headers",
+    ],
+}
diff --git a/libs/android_runtime_lazy/android_runtime_lazy.cpp b/libs/android_runtime_lazy/android_runtime_lazy.cpp
new file mode 100644
index 0000000..98d8e8a
--- /dev/null
+++ b/libs/android_runtime_lazy/android_runtime_lazy.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "ANDROID_RUNTIME_LAZY"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_util_Binder.h"
+
+#include <dlfcn.h>
+#include <mutex>
+
+#include <log/log.h>
+
+namespace android {
+namespace {
+
+std::once_flag loadFlag;
+
+typedef JNIEnv* (*getJNIEnv_t)();
+typedef sp<IBinder> (*ibinderForJavaObject_t)(JNIEnv* env, jobject obj);
+typedef jobject (*javaObjectForIBinder_t)(JNIEnv* env, const sp<IBinder>& val);
+
+getJNIEnv_t _getJNIEnv;
+ibinderForJavaObject_t _ibinderForJavaObject;
+javaObjectForIBinder_t _javaObjectForIBinder;
+
+void load() {
+    std::call_once(loadFlag, []() {
+        void* handle = dlopen("libandroid_runtime.so", RTLD_LAZY);
+        if (handle == nullptr) {
+            ALOGE("Could not open libandroid_runtime.");
+            return;
+        }
+
+        _getJNIEnv = reinterpret_cast<getJNIEnv_t>(
+                dlsym(handle, "_ZN7android14AndroidRuntime9getJNIEnvEv"));
+        if (_getJNIEnv == nullptr) {
+            ALOGW("Could not find getJNIEnv.");
+            // no return
+        }
+
+        _ibinderForJavaObject = reinterpret_cast<ibinderForJavaObject_t>(
+                dlsym(handle, "_ZN7android20ibinderForJavaObjectEP7_JNIEnvP8_jobject"));
+        if (_ibinderForJavaObject == nullptr) {
+            ALOGW("Could not find ibinderForJavaObject.");
+            // no return
+        }
+
+        _javaObjectForIBinder = reinterpret_cast<javaObjectForIBinder_t>(
+                dlsym(handle,
+                      "_ZN7android20javaObjectForIBinderEP7_JNIEnvRKNS_2spINS_7IBinderEEE"));
+        if (_javaObjectForIBinder == nullptr) {
+            ALOGW("Could not find javaObjectForIBinder.");
+            // no return
+        }
+    });
+}
+
+} // namespace
+
+// exports delegate functions
+
+JNIEnv* AndroidRuntime::getJNIEnv() {
+    load();
+    if (_getJNIEnv == nullptr) {
+        return nullptr;
+    }
+    return _getJNIEnv();
+}
+
+sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) {
+    load();
+    if (_ibinderForJavaObject == nullptr) {
+        return nullptr;
+    }
+    return _ibinderForJavaObject(env, obj);
+}
+
+jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) {
+    load();
+    if (_javaObjectForIBinder == nullptr) {
+        return nullptr;
+    }
+    return _javaObjectForIBinder(env, val);
+}
+
+} // namespace android
diff --git a/libs/android_runtime_lazy/include/android_runtime/AndroidRuntime.h b/libs/android_runtime_lazy/include/android_runtime/AndroidRuntime.h
new file mode 100644
index 0000000..85231fa
--- /dev/null
+++ b/libs/android_runtime_lazy/include/android_runtime/AndroidRuntime.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "jni.h"
+
+namespace android {
+
+// Intentionally use the same name with AndroidRuntime in frameworks/base/core/jni/
+// to make the client use this in the same way with the original class.
+class AndroidRuntime {
+public:
+    static JNIEnv* getJNIEnv();
+};
+
+} // namespace android
diff --git a/libs/android_runtime_lazy/include/android_util_Binder.h b/libs/android_runtime_lazy/include/android_util_Binder.h
new file mode 100644
index 0000000..e47390e
--- /dev/null
+++ b/libs/android_runtime_lazy/include/android_util_Binder.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IBinder.h>
+#include "jni.h"
+
+namespace android {
+
+// The name of this file is same with the file in frameworks/base/core/jni/
+// This is intentional to make the client use these exported functions
+// in the same way with the original.
+
+jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val);
+sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj);
+
+} // namespace android
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index afdfe4f..e5219a5 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -20,6 +20,8 @@
 #include <string>
 #include <vector>
 
+#include <linux/android/binder.h>
+
 #include <android-base/unique_fd.h>
 #include <cutils/native_handle.h>
 #include <utils/Errors.h>
@@ -28,7 +30,6 @@
 #include <utils/Vector.h>
 #include <utils/Flattenable.h>
 
-#include <binder/binder_kernel.h>
 #include <binder/IInterface.h>
 #include <binder/Parcelable.h>
 #include <binder/Map.h>
diff --git a/libs/binder/include/binder/binder_kernel.h b/libs/binder/include/binder/binder_kernel.h
deleted file mode 100644
index c7f6b4b..0000000
--- a/libs/binder/include/binder/binder_kernel.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_BINDER_KERNEL_H
-#define ANDROID_BINDER_KERNEL_H
-
-#include <linux/android/binder.h>
-
-/**
- * This file exists because the uapi kernel headers in bionic are built
- * from upstream kernel headers only, and not all of the hwbinder kernel changes
- * have made it upstream yet. Therefore, the modifications to the
- * binder header are added locally in this file.
- */
-
-enum {
-        FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000,
-};
-
-#define BINDER_SET_CONTEXT_MGR_EXT      _IOW('b', 13, struct flat_binder_object)
-
-struct binder_transaction_data_secctx {
-        struct binder_transaction_data transaction_data;
-        binder_uintptr_t secctx;
-};
-
-enum {
-        BR_TRANSACTION_SEC_CTX = _IOR('r', 2,
-                              struct binder_transaction_data_secctx),
-};
-
-#endif // ANDROID_BINDER_KERNEL_H
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index a96c9a0..21bef2e 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -39,17 +39,12 @@
     ],
 
     shared_libs: [
+        "libandroid_runtime_lazy",
         "libbase",
         "libbinder",
         "libutils",
     ],
 
-    required: [
-        // libbinder_ndk may be used by Java and non-Java things. When lower-level things use it,
-        // they shouldn't have to take on the cost of loading libandroid_runtime.
-        "libandroid_runtime",
-    ],
-
     header_libs: [
         "jni_headers",
     ],
diff --git a/libs/binder/ndk/ibinder_jni.cpp b/libs/binder/ndk/ibinder_jni.cpp
index 4a31080..d931785 100644
--- a/libs/binder/ndk/ibinder_jni.cpp
+++ b/libs/binder/ndk/ibinder_jni.cpp
@@ -17,69 +17,19 @@
 #include <android/binder_ibinder_jni.h>
 #include "ibinder_internal.h"
 
-#include <android-base/logging.h>
-#include <binder/IBinder.h>
-
-#include <mutex>
-
-#include <dlfcn.h>
+#include <android_util_Binder.h>
 
 using ::android::IBinder;
+using ::android::ibinderForJavaObject;
+using ::android::javaObjectForIBinder;
 using ::android::sp;
 
-struct LazyAndroidRuntime {
-    typedef sp<IBinder> (*FromJava)(JNIEnv* env, jobject obj);
-    typedef jobject (*ToJava)(JNIEnv* env, const sp<IBinder>& val);
-
-    static FromJava ibinderForJavaObject;
-    static ToJava javaObjectForIBinder;
-
-    static void load() {
-        std::call_once(mLoadFlag, []() {
-            void* handle = dlopen("libandroid_runtime.so", RTLD_LAZY);
-            if (handle == nullptr) {
-                LOG(WARNING) << "Could not open libandroid_runtime.";
-                return;
-            }
-
-            ibinderForJavaObject = reinterpret_cast<FromJava>(
-                    dlsym(handle, "_ZN7android20ibinderForJavaObjectEP7_JNIEnvP8_jobject"));
-            if (ibinderForJavaObject == nullptr) {
-                LOG(WARNING) << "Could not find ibinderForJavaObject.";
-                // no return
-            }
-
-            javaObjectForIBinder = reinterpret_cast<ToJava>(dlsym(
-                    handle, "_ZN7android20javaObjectForIBinderEP7_JNIEnvRKNS_2spINS_7IBinderEEE"));
-            if (javaObjectForIBinder == nullptr) {
-                LOG(WARNING) << "Could not find javaObjectForIBinder.";
-                // no return
-            }
-        });
-    }
-
-   private:
-    static std::once_flag mLoadFlag;
-
-    LazyAndroidRuntime(){};
-};
-
-LazyAndroidRuntime::FromJava LazyAndroidRuntime::ibinderForJavaObject = nullptr;
-LazyAndroidRuntime::ToJava LazyAndroidRuntime::javaObjectForIBinder = nullptr;
-std::once_flag LazyAndroidRuntime::mLoadFlag;
-
 AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder) {
     if (binder == nullptr) {
         return nullptr;
     }
 
-    LazyAndroidRuntime::load();
-    if (LazyAndroidRuntime::ibinderForJavaObject == nullptr) {
-        return nullptr;
-    }
-
-    sp<IBinder> ibinder = (LazyAndroidRuntime::ibinderForJavaObject)(env, binder);
-
+    sp<IBinder> ibinder = ibinderForJavaObject(env, binder);
     sp<AIBinder> cbinder = ABpBinder::lookupOrCreateFromBinder(ibinder);
     AIBinder_incStrong(cbinder.get());
 
@@ -91,10 +41,5 @@
         return nullptr;
     }
 
-    LazyAndroidRuntime::load();
-    if (LazyAndroidRuntime::javaObjectForIBinder == nullptr) {
-        return nullptr;
-    }
-
-    return (LazyAndroidRuntime::javaObjectForIBinder)(env, binder->getBinder());
+    return javaObjectForIBinder(env, binder->getBinder());
 }
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index b29b6e7..8cd4e03 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -41,7 +41,7 @@
     name: "test_libbinder_ndk_test_defaults",
     defaults: ["test_libbinder_ndk_defaults"],
     shared_libs: [
-        "libandroid_runtime",
+        "libandroid_runtime_lazy",
         "libbase",
         "libbinder",
         "libutils",
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 9dde15d..14eca43 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -781,6 +781,10 @@
             int result = dequeueBuffer(&buf, &fence, width, height, format, usage, &bufferAge,
                                        getTimestamps ? &frameTimestamps : nullptr);
 
+            if (fence == nullptr) {
+                ALOGE("dequeueBuffer returned a NULL fence, setting to Fence::NO_FENCE");
+                fence = Fence::NO_FENCE;
+            }
             reply->writeInt32(buf);
             reply->write(*fence);
             reply->writeUint64(bufferAge);
@@ -963,6 +967,10 @@
                 ALOGE("getLastQueuedBuffer failed to write buffer: %d", result);
                 return result;
             }
+            if (fence == nullptr) {
+                ALOGE("getLastQueuedBuffer returned a NULL fence, setting to Fence::NO_FENCE");
+                fence = Fence::NO_FENCE;
+            }
             result = reply->write(*fence);
             if (result != NO_ERROR) {
                 ALOGE("getLastQueuedBuffer failed to write fence: %d", result);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 247dc8d..b74d675 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -68,7 +68,9 @@
                                      const Vector<DisplayState>& displays, uint32_t flags,
                                      const sp<IBinder>& applyToken,
                                      const InputWindowCommands& commands,
-                                     int64_t desiredPresentTime) {
+                                     int64_t desiredPresentTime,
+                                     const cached_buffer_t& uncacheBuffer,
+                                     const std::vector<ListenerCallbacks>& listenerCallbacks) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
 
@@ -86,6 +88,16 @@
         data.writeStrongBinder(applyToken);
         commands.write(data);
         data.writeInt64(desiredPresentTime);
+        data.writeStrongBinder(uncacheBuffer.token);
+        data.writeUint64(uncacheBuffer.cacheId);
+
+        if (data.writeVectorSize(listenerCallbacks) == NO_ERROR) {
+            for (const auto& [listener, callbackIds] : listenerCallbacks) {
+                data.writeStrongBinder(IInterface::asBinder(listener));
+                data.writeInt64Vector(callbackIds);
+            }
+        }
+
         remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
     }
 
@@ -970,8 +982,23 @@
             inputWindowCommands.read(data);
 
             int64_t desiredPresentTime = data.readInt64();
+
+            cached_buffer_t uncachedBuffer;
+            uncachedBuffer.token = data.readStrongBinder();
+            uncachedBuffer.cacheId = data.readUint64();
+
+            std::vector<ListenerCallbacks> listenerCallbacks;
+            int32_t listenersSize = data.readInt32();
+            for (int32_t i = 0; i < listenersSize; i++) {
+                auto listener =
+                        interface_cast<ITransactionCompletedListener>(data.readStrongBinder());
+                std::vector<CallbackId> callbackIds;
+                data.readInt64Vector(&callbackIds);
+                listenerCallbacks.emplace_back(listener, callbackIds);
+            }
+
             setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
-                                desiredPresentTime);
+                                desiredPresentTime, uncachedBuffer, listenerCallbacks);
             return NO_ERROR;
         }
         case BOOT_FINISHED: {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 84ba644..3077b21 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -86,16 +86,9 @@
     memcpy(output.writeInplace(16 * sizeof(float)),
            colorTransform.asArray(), 16 * sizeof(float));
     output.writeFloat(cornerRadius);
-
-    if (output.writeVectorSize(listenerCallbacks) == NO_ERROR) {
-        for (const auto& [listener, callbackIds] : listenerCallbacks) {
-            output.writeStrongBinder(IInterface::asBinder(listener));
-            output.writeInt64Vector(callbackIds);
-        }
-    }
-
+    output.writeBool(hasListenerCallbacks);
     output.writeStrongBinder(cachedBuffer.token);
-    output.writeInt32(cachedBuffer.bufferId);
+    output.writeUint64(cachedBuffer.cacheId);
     output.writeParcelable(metadata);
 
     output.writeFloat(bgColorAlpha);
@@ -163,17 +156,9 @@
 
     colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
     cornerRadius = input.readFloat();
-
-    int32_t listenersSize = input.readInt32();
-    for (int32_t i = 0; i < listenersSize; i++) {
-        auto listener = interface_cast<ITransactionCompletedListener>(input.readStrongBinder());
-        std::vector<CallbackId> callbackIds;
-        input.readInt64Vector(&callbackIds);
-        listenerCallbacks.emplace_back(listener, callbackIds);
-    }
-
+    hasListenerCallbacks = input.readBool();
     cachedBuffer.token = input.readStrongBinder();
-    cachedBuffer.bufferId = input.readInt32();
+    cachedBuffer.cacheId = input.readUint64();
     input.readParcelable(&metadata);
 
     bgColorAlpha = input.readFloat();
@@ -376,9 +361,9 @@
         what |= eColorTransformChanged;
         colorTransform = other.colorTransform;
     }
-    if (other.what & eListenerCallbacksChanged) {
-        what |= eListenerCallbacksChanged;
-        listenerCallbacks = other.listenerCallbacks;
+    if (other.what & eHasListenerCallbacksChanged) {
+        what |= eHasListenerCallbacksChanged;
+        hasListenerCallbacks = other.hasListenerCallbacks;
     }
 
 #ifndef NO_INPUT
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index b0e8275..84aed5f 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -233,6 +233,8 @@
 
 // ---------------------------------------------------------------------------
 
+void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId);
+
 class BufferCache : public Singleton<BufferCache> {
 public:
     BufferCache() : token(new BBinder()) {}
@@ -241,77 +243,57 @@
         return IInterface::asBinder(TransactionCompletedListener::getIInstance());
     }
 
-    int32_t getId(const sp<GraphicBuffer>& buffer) {
+    status_t getCacheId(const sp<GraphicBuffer>& buffer, uint64_t* cacheId) {
         std::lock_guard<std::mutex> lock(mMutex);
 
-        auto itr = mBuffers.find(buffer);
+        auto itr = mBuffers.find(buffer->getId());
         if (itr == mBuffers.end()) {
-            return -1;
+            return BAD_VALUE;
         }
-        itr->second.counter = getCounter();
-        return itr->second.id;
+        itr->second = getCounter();
+        *cacheId = buffer->getId();
+        return NO_ERROR;
     }
 
-    int32_t cache(const sp<GraphicBuffer>& buffer) {
+    uint64_t cache(const sp<GraphicBuffer>& buffer) {
         std::lock_guard<std::mutex> lock(mMutex);
 
-        int32_t bufferId = getNextAvailableId();
+        if (mBuffers.size() >= BUFFER_CACHE_MAX_SIZE) {
+            evictLeastRecentlyUsedBuffer();
+        }
 
-        mBuffers[buffer].id = bufferId;
-        mBuffers[buffer].counter = getCounter();
-        return bufferId;
+        buffer->addDeathCallback(bufferCacheCallback, nullptr);
+
+        mBuffers[buffer->getId()] = getCounter();
+        return buffer->getId();
+    }
+
+    void uncache(uint64_t cacheId) {
+        std::lock_guard<std::mutex> lock(mMutex);
+        uncacheLocked(cacheId);
+    }
+
+    void uncacheLocked(uint64_t cacheId) REQUIRES(mMutex) {
+        mBuffers.erase(cacheId);
+        SurfaceComposerClient::doUncacheBufferTransaction(cacheId);
     }
 
 private:
-    int32_t evictDestroyedBuffer() REQUIRES(mMutex) {
+    void evictLeastRecentlyUsedBuffer() REQUIRES(mMutex) {
         auto itr = mBuffers.begin();
-        while (itr != mBuffers.end()) {
-            auto& buffer = itr->first;
-            if (buffer == nullptr || buffer.promote() == nullptr) {
-                int32_t bufferId = itr->second.id;
-                mBuffers.erase(itr);
-                return bufferId;
-            }
-            itr++;
-        }
-        return -1;
-    }
-
-    int32_t evictLeastRecentlyUsedBuffer() REQUIRES(mMutex) {
-        if (mBuffers.size() < 0) {
-            return -1;
-        }
-        auto itr = mBuffers.begin();
-        uint64_t minCounter = itr->second.counter;
+        uint64_t minCounter = itr->second;
         auto minBuffer = itr;
         itr++;
 
         while (itr != mBuffers.end()) {
-            uint64_t counter = itr->second.counter;
+            uint64_t counter = itr->second;
             if (counter < minCounter) {
                 minCounter = counter;
                 minBuffer = itr;
             }
             itr++;
         }
-        int32_t minBufferId = minBuffer->second.id;
-        mBuffers.erase(minBuffer);
-        return minBufferId;
-    }
-
-    int32_t getNextAvailableId() REQUIRES(mMutex) {
-        static int32_t id = 0;
-        if (id + 1 < BUFFER_CACHE_MAX_SIZE) {
-            return id++;
-        }
-
-        // There are no more valid cache ids. To set additional buffers, evict existing buffers
-        // and reuse their cache ids.
-        int32_t bufferId = evictDestroyedBuffer();
-        if (bufferId > 0) {
-            return bufferId;
-        }
-        return evictLeastRecentlyUsedBuffer();
+        uncacheLocked(minBuffer->first);
     }
 
     uint64_t getCounter() REQUIRES(mMutex) {
@@ -319,18 +301,8 @@
         return counter++;
     }
 
-    struct Metadata {
-        // The cache id of a buffer that can be set to ISurfaceComposer. When ISurfaceComposer
-        // recieves this id, it can retrieve the buffer from its cache. Caching GraphicBuffers
-        // is important because sending them across processes is expensive.
-        int32_t id = 0;
-        // When a buffer is set, a counter is incremented and stored in the cache's metadata.
-        // When an buffer must be evicted, the entry with the lowest counter value is chosen.
-        uint64_t counter = 0;
-    };
-
     std::mutex mMutex;
-    std::map<wp<GraphicBuffer>, Metadata> mBuffers GUARDED_BY(mMutex);
+    std::map<uint64_t /*Cache id*/, uint64_t /*counter*/> mBuffers GUARDED_BY(mMutex);
 
     // Used by ISurfaceComposer to identify which process is sending the cached buffer.
     sp<IBinder> token;
@@ -338,6 +310,11 @@
 
 ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache);
 
+void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId) {
+    // GraphicBuffer id's are used as the cache ids.
+    BufferCache::getInstance().uncache(graphicBufferId);
+}
+
 // ---------------------------------------------------------------------------
 
 SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
@@ -385,6 +362,9 @@
     mInputWindowCommands.merge(other.mInputWindowCommands);
     other.mInputWindowCommands.clear();
 
+    mContainsBuffer = other.mContainsBuffer;
+    other.mContainsBuffer = false;
+
     return *this;
 }
 
@@ -401,7 +381,50 @@
     s.state.parentHandleForChild = nullptr;
 
     composerStates.add(s);
-    sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1);
+    sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1, {}, {});
+}
+
+void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+    cached_buffer_t uncacheBuffer;
+    uncacheBuffer.token = BufferCache::getInstance().getToken();
+    uncacheBuffer.cacheId = cacheId;
+
+    sf->setTransactionState({}, {}, 0, nullptr, {}, -1, uncacheBuffer, {});
+}
+
+void SurfaceComposerClient::Transaction::cacheBuffers() {
+    if (!mContainsBuffer) {
+        return;
+    }
+
+    size_t count = 0;
+    for (auto& [sc, cs] : mComposerStates) {
+        layer_state_t* s = getLayerState(sc);
+        if (!(s->what & layer_state_t::eBufferChanged)) {
+            continue;
+        }
+
+        uint64_t cacheId = 0;
+        status_t ret = BufferCache::getInstance().getCacheId(s->buffer, &cacheId);
+        if (ret == NO_ERROR) {
+            s->what &= ~static_cast<uint32_t>(layer_state_t::eBufferChanged);
+            s->buffer = nullptr;
+        } else {
+            cacheId = BufferCache::getInstance().cache(s->buffer);
+        }
+        s->what |= layer_state_t::eCachedBufferChanged;
+        s->cachedBuffer.token = BufferCache::getInstance().getToken();
+        s->cachedBuffer.cacheId = cacheId;
+
+        // If we have more buffers than the size of the cache, we should stop caching so we don't
+        // evict other buffers in this transaction
+        count++;
+        if (count >= BUFFER_CACHE_MAX_SIZE) {
+            break;
+        }
+    }
 }
 
 status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
@@ -411,6 +434,8 @@
 
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
 
+    std::vector<ListenerCallbacks> listenerCallbacks;
+
     // For every listener with registered callbacks
     for (const auto& [listener, callbackInfo] : mListenerCallbacks) {
         auto& [callbackIds, surfaceControls] = callbackInfo;
@@ -418,11 +443,7 @@
             continue;
         }
 
-        // If the listener does not have any SurfaceControls set on this Transaction, send the
-        // callback now
-        if (surfaceControls.empty()) {
-            listener->onTransactionCompleted(ListenerStats::createEmpty(listener, callbackIds));
-        }
+        listenerCallbacks.emplace_back(listener, std::move(callbackIds));
 
         // If the listener has any SurfaceControls set on this Transaction update the surface state
         for (const auto& surfaceControl : surfaceControls) {
@@ -431,12 +452,14 @@
                 ALOGE("failed to get layer state");
                 continue;
             }
-            s->what |= layer_state_t::eListenerCallbacksChanged;
-            s->listenerCallbacks.emplace_back(listener, std::move(callbackIds));
+            s->what |= layer_state_t::eHasListenerCallbacksChanged;
+            s->hasListenerCallbacks = true;
         }
     }
     mListenerCallbacks.clear();
 
+    cacheBuffers();
+
     Vector<ComposerState> composerStates;
     Vector<DisplayState> displayStates;
     uint32_t flags = 0;
@@ -468,7 +491,9 @@
 
     sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
     sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
-                            mDesiredPresentTime);
+                            mDesiredPresentTime,
+                            {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
+                            listenerCallbacks);
     mInputWindowCommands.clear();
     mStatus = NO_ERROR;
     return NO_ERROR;
@@ -882,20 +907,12 @@
         mStatus = BAD_INDEX;
         return *this;
     }
-
-    int32_t bufferId = BufferCache::getInstance().getId(buffer);
-    if (bufferId < 0) {
-        bufferId = BufferCache::getInstance().cache(buffer);
-
-        s->what |= layer_state_t::eBufferChanged;
-        s->buffer = buffer;
-    }
-
-    s->what |= layer_state_t::eCachedBufferChanged;
-    s->cachedBuffer.token = BufferCache::getInstance().getToken();
-    s->cachedBuffer.bufferId = bufferId;
+    s->what |= layer_state_t::eBufferChanged;
+    s->buffer = buffer;
 
     registerSurfaceControlForCallback(sc);
+
+    mContainsBuffer = true;
     return *this;
 }
 
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 3dffa8f..fe85fdf 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -20,13 +20,10 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
 #include <binder/IInterface.h>
 
+#include <gui/ITransactionCompletedListener.h>
+
 #include <ui/ConfigStoreTypes.h>
 #include <ui/DisplayedFrameStats.h>
 #include <ui/FrameStats.h>
@@ -34,12 +31,18 @@
 #include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
 #include <optional>
 #include <vector>
 
 namespace android {
 // ----------------------------------------------------------------------------
 
+struct cached_buffer_t;
 struct ComposerState;
 struct DisplayState;
 struct DisplayInfo;
@@ -131,7 +134,9 @@
                                      const Vector<DisplayState>& displays, uint32_t flags,
                                      const sp<IBinder>& applyToken,
                                      const InputWindowCommands& inputWindowCommands,
-                                     int64_t desiredPresentTime) = 0;
+                                     int64_t desiredPresentTime,
+                                     const cached_buffer_t& uncacheBuffer,
+                                     const std::vector<ListenerCallbacks>& listenerCallbacks) = 0;
 
     /* signal that we're done booting.
      * Requires ACCESS_SURFACE_FLINGER permission
@@ -194,8 +199,7 @@
      * of the buffer. The caller should pick the data space and pixel format
      * that it can consume.
      *
-     * At the moment, sourceCrop is ignored and is always set to the visible
-     * region (projected display viewport) of the screen.
+     * sourceCrop is the crop on the logical display.
      *
      * reqWidth and reqHeight specifies the size of the buffer.  When either
      * of them is 0, they are set to the size of the logical display viewport.
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 35e795c..2256497 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -23,7 +23,6 @@
 #include <utils/Errors.h>
 
 #include <gui/IGraphicBufferProducer.h>
-#include <gui/ITransactionCompletedListener.h>
 #include <math/mat4.h>
 
 #ifndef NO_INPUT
@@ -41,6 +40,11 @@
 class Parcel;
 class ISurfaceComposerClient;
 
+struct cached_buffer_t {
+    sp<IBinder> token = nullptr;
+    uint64_t cacheId;
+};
+
 /*
  * Used to communicate layer information between SurfaceFlinger and its clients.
  */
@@ -81,7 +85,7 @@
         eApiChanged = 0x04000000,
         eSidebandStreamChanged = 0x08000000,
         eColorTransformChanged = 0x10000000,
-        eListenerCallbacksChanged = 0x20000000,
+        eHasListenerCallbacksChanged = 0x20000000,
         eInputInfoChanged = 0x40000000,
         eCornerRadiusChanged = 0x80000000,
         eFrameChanged = 0x1'00000000,
@@ -115,6 +119,7 @@
             surfaceDamageRegion(),
             api(-1),
             colorTransform(mat4()),
+            hasListenerCallbacks(false),
             bgColorAlpha(0),
             bgColorDataspace(ui::Dataspace::UNKNOWN),
             colorSpaceAgnostic(false) {
@@ -133,10 +138,6 @@
         float dtdy{0};
         float dsdy{0};
     };
-    struct cached_buffer_t {
-        sp<IBinder> token = nullptr;
-        int32_t bufferId = -1;
-    };
     sp<IBinder> surface;
     uint64_t what;
     float x;
@@ -181,7 +182,7 @@
     sp<NativeHandle> sidebandStream;
     mat4 colorTransform;
 
-    std::vector<ListenerCallbacks> listenerCallbacks;
+    bool hasListenerCallbacks;
 #ifndef NO_INPUT
     InputWindowInfo inputInfo;
 #endif
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 39d6d13..593a5e7 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -165,6 +165,12 @@
     static void doDropReferenceTransaction(const sp<IBinder>& handle,
             const sp<ISurfaceComposerClient>& client);
 
+    /**
+     * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is
+     * in order with other transactions that use buffers.
+     */
+    static void doUncacheBufferTransaction(uint64_t cacheId);
+
     // Queries whether a given display is wide color display.
     static status_t isWideColorDisplay(const sp<IBinder>& display, bool* outIsWideColorDisplay);
 
@@ -279,6 +285,9 @@
         bool                        mAnimation = false;
         bool                        mEarlyWakeup = false;
 
+        // Indicates that the Transaction contains a buffer that should be cached
+        bool mContainsBuffer = false;
+
         // mDesiredPresentTime is the time in nanoseconds that the client would like the transaction
         // to be presented. When it is not possible to present at exactly that time, it will be
         // presented after the time has passed.
@@ -297,6 +306,7 @@
         layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
         DisplayState& getDisplayState(const sp<IBinder>& token);
 
+        void cacheBuffers();
         void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
 
     public:
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 06fe86c..0ee9bff 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -560,7 +560,10 @@
                              const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
                              const sp<IBinder>& /*applyToken*/,
                              const InputWindowCommands& /*inputWindowCommands*/,
-                             int64_t /*desiredPresentTime*/) override {}
+                             int64_t /*desiredPresentTime*/,
+                             const cached_buffer_t& /*cachedBuffer*/,
+                             const std::vector<ListenerCallbacks>& /*listenerCallbacks*/) override {
+    }
 
     void bootFinished() override {}
     bool authenticateSurfaceTexture(
diff --git a/libs/incidentcompanion/Android.bp b/libs/incidentcompanion/Android.bp
index 45eab00..63411b9 100644
--- a/libs/incidentcompanion/Android.bp
+++ b/libs/incidentcompanion/Android.bp
@@ -35,8 +35,12 @@
     },
     srcs: [
         ":incidentcompanion_aidl",
+        "src/IncidentManager.cpp",
     ],
-    export_include_dirs: ["binder"],
+    export_include_dirs: [
+        "binder",
+        "include",
+    ],
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl b/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl
index 6bf98d2..98c2814 100644
--- a/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl
+++ b/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.os.IIncidentAuthListener;
+import android.os.IncidentManager;
 
 /**
  * Helper service for incidentd and dumpstated to provide user feedback
@@ -35,6 +36,10 @@
      *      returns via the callback whether the application should be trusted.  It is up
      *      to the caller to actually implement the restriction to take or not take
      *      the incident or bug report.
+     * @param receiverClass The class that will be the eventual broacast receiver for the
+     *      INCIDENT_REPORT_READY message. Used as part of the id in incidentd.
+     * @param reportId The incident report ID.  Incidentd should call with this parameter, but
+     *     everyone else should pass null or empty string.
      * @param flags FLAG_CONFIRMATION_DIALOG (0x1) - to show this as a dialog.  Otherwise
      *      a dialog will be shown as a notification.
      * @param callback Interface to receive results.  The results may not come back for
@@ -44,6 +49,7 @@
      *      to send their report.
      */
     oneway void authorizeReport(int callingUid, String callingPackage,
+            String receiverClass, String reportId,
             int flags, IIncidentAuthListener callback);
 
     /**
@@ -52,6 +58,11 @@
     oneway void cancelAuthorization(IIncidentAuthListener callback);
 
     /**
+     * Send the report ready broadcast on behalf of incidentd.
+     */
+    oneway void sendReportReadyBroadcast(String pkg, String cls);
+
+    /**
      * Return the list of pending approvals.
      */
     List<String> getPendingReports();
@@ -69,4 +80,26 @@
      * @param uri the report.
      */
     void denyReport(String uri);
+
+    /**
+     * List the incident reports for the given ComponentName.  The receiver
+     * must be for a package inside the caller.
+     */
+    List<String> getIncidentReportList(String pkg, String cls);
+
+    /**
+     * Get the IncidentReport object.
+     */
+    IncidentManager.IncidentReport getIncidentReport(String pkg, String cls, String id);
+
+    /**
+     * Signal that the client is done with this incident report and it can be deleted.
+     */
+    void deleteIncidentReports(String pkg, String cls, String id);
+
+    /**
+     * Signal that the client is done with all incident reports from this package.
+     * Especially useful for testing.
+     */
+    void deleteAllIncidentReports(String pkg);
 }
diff --git a/libs/incidentcompanion/binder/android/os/IncidentManager.aidl b/libs/incidentcompanion/binder/android/os/IncidentManager.aidl
new file mode 100644
index 0000000..d17823e
--- /dev/null
+++ b/libs/incidentcompanion/binder/android/os/IncidentManager.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+parcelable IncidentManager.IncidentReport cpp_header "android/os/IncidentManager.h";
+
diff --git a/libs/incidentcompanion/include/android/os/IncidentManager.h b/libs/incidentcompanion/include/android/os/IncidentManager.h
new file mode 100644
index 0000000..07b6d82
--- /dev/null
+++ b/libs/incidentcompanion/include/android/os/IncidentManager.h
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <utils/String16.h>
+
+#include <set>
+#include <vector>
+
+namespace android {
+namespace os {
+
+class IncidentManager : public virtual RefBase {
+public:
+    class IncidentReport : public Parcelable {
+    public:
+        IncidentReport();
+        virtual ~IncidentReport();
+
+        virtual status_t writeToParcel(Parcel* out) const;
+        virtual status_t readFromParcel(const Parcel* in);
+
+        void setTimestampNs(int64_t val) { mTimestampNs = val; }
+        int64_t getTimestampNs() const { return mTimestampNs; }
+        int64_t getTimestampMs() const { return mTimestampNs / 1000000; }
+
+        void setPrivacyPolicy(int32_t val) { mPrivacyPolicy = val; }
+        // This was accidentally published as a long in the java api.
+        int64_t getPrivacyPolicy() const { return mPrivacyPolicy; }
+        // Dups the fd, so you retain ownership of the original one.  If there is a
+        // previously set fd, closes that, since this object owns its own fd.
+        status_t setFileDescriptor(int fd);
+
+        // Does not dup the fd, so ownership is passed to this object.  If there is a
+        // previously set fd, closes that, since this object owns its own fd.
+        void takeFileDescriptor(int fd);
+
+        // Returns the fd, which you don't own.  Call dup if you need a copy.
+        int getFileDescriptor() const { return mFileDescriptor; }
+
+    private:
+        int64_t mTimestampNs;
+        int32_t mPrivacyPolicy;
+        int mFileDescriptor;
+    };
+
+
+private:
+    // Not implemented for now.
+    IncidentManager();
+    virtual ~IncidentManager();
+};
+}
+}
+
diff --git a/libs/incidentcompanion/src/IncidentManager.cpp b/libs/incidentcompanion/src/IncidentManager.cpp
new file mode 100644
index 0000000..f7c8a5e
--- /dev/null
+++ b/libs/incidentcompanion/src/IncidentManager.cpp
@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/os/IncidentManager.h>
+
+namespace android {
+namespace os {
+
+// ============================================================
+IncidentManager::IncidentReport::IncidentReport()
+        :mTimestampNs(0),
+         mPrivacyPolicy(0),
+         mFileDescriptor(-1) {
+}
+
+IncidentManager::IncidentReport::~IncidentReport() {
+    if (mFileDescriptor >= 0) {
+        close(mFileDescriptor);
+    }
+}
+
+status_t IncidentManager::IncidentReport::writeToParcel(Parcel* out) const {
+    status_t err;
+
+    err = out->writeInt64(mTimestampNs);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+
+    err = out->writeInt32(mPrivacyPolicy);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (mFileDescriptor >= 0) {
+        err = out->writeInt32(1);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        err = out->writeDupParcelFileDescriptor(mFileDescriptor);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+    } else {
+        err = out->writeInt32(0);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t IncidentManager::IncidentReport::readFromParcel(const Parcel* in) {
+    status_t err;
+    int32_t hasField;
+
+    err = in->readInt64(&mTimestampNs);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    err = in->readInt32(&mPrivacyPolicy);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    err = in->readInt32(&hasField);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (hasField) {
+        int fd = in->readParcelFileDescriptor();
+        if (fd >= 0) {
+            mFileDescriptor = dup(fd);
+            if (mFileDescriptor < 0) {
+                return -errno;
+            }
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t IncidentManager::IncidentReport::setFileDescriptor(int fd) {
+    if (mFileDescriptor >= 0) {
+        close(mFileDescriptor);
+    }
+    if (fd < 0) {
+        mFileDescriptor = -1;
+    } else {
+        mFileDescriptor = dup(fd);
+        if (mFileDescriptor < 0) {
+            return -errno;
+        }
+    }
+    return NO_ERROR;
+}
+
+void IncidentManager::IncidentReport::takeFileDescriptor(int fd) {
+    if (mFileDescriptor >= 0) {
+        close(mFileDescriptor);
+    }
+    if (fd < 0) {
+        mFileDescriptor = -1;
+    } else {
+        mFileDescriptor = fd;
+    }
+}
+
+// ============================================================
+IncidentManager::~IncidentManager() {
+}
+
+}
+}
+
+
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index 4ce5a10..d6a73bf 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -30,7 +30,7 @@
     explicit BpInputFlinger(const sp<IBinder>& impl) :
             BpInterface<IInputFlinger>(impl) { }
 
-    virtual void setInputWindows(const Vector<InputWindowInfo>& inputInfo,
+    virtual void setInputWindows(const std::vector<InputWindowInfo>& inputInfo,
             const sp<ISetInputWindowsListener>& setInputWindowsListener) {
         Parcel data, reply;
         data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
@@ -81,10 +81,9 @@
         if (count > data.dataSize()) {
             return BAD_VALUE;
         }
-        Vector<InputWindowInfo> handles;
-        handles.setCapacity(count);
+        std::vector<InputWindowInfo> handles;
         for (size_t i = 0; i < count; i++) {
-            handles.add(InputWindowInfo(data));
+            handles.push_back(InputWindowInfo::read(data));
         }
         const sp<ISetInputWindowsListener> setInputWindowsListener =
                 ISetInputWindowsListener::asInterface(data.readStrongBinder());
diff --git a/libs/input/InputApplication.cpp b/libs/input/InputApplication.cpp
index 7936f50..1d9f8a7 100644
--- a/libs/input/InputApplication.cpp
+++ b/libs/input/InputApplication.cpp
@@ -24,19 +24,10 @@
 
 // --- InputApplicationHandle ---
 
-InputApplicationHandle::InputApplicationHandle() :
-    mInfo(nullptr) {
+InputApplicationHandle::InputApplicationHandle() {
 }
 
 InputApplicationHandle::~InputApplicationHandle() {
-    delete mInfo;
-}
-
-void InputApplicationHandle::releaseInfo() {
-    if (mInfo) {
-        delete mInfo;
-        mInfo = nullptr;
-    }
 }
 
 InputApplicationInfo InputApplicationInfo::read(const Parcel& from) {
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index dab6eac..4db9e06 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -186,7 +186,7 @@
         int32_t axis, uint32_t source) const {
     size_t numRanges = mMotionRanges.size();
     for (size_t i = 0; i < numRanges; i++) {
-        const MotionRange& range = mMotionRanges.itemAt(i);
+        const MotionRange& range = mMotionRanges[i];
         if (range.axis == axis && range.source == source) {
             return &range;
         }
@@ -201,11 +201,11 @@
 void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
         float flat, float fuzz, float resolution) {
     MotionRange range = { axis, source, min, max, flat, fuzz, resolution };
-    mMotionRanges.add(range);
+    mMotionRanges.push_back(range);
 }
 
 void InputDeviceInfo::addMotionRange(const MotionRange& range) {
-    mMotionRanges.add(range);
+    mMotionRanges.push_back(range);
 }
 
 } // namespace android
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index 88cb0db..efca68d 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -120,11 +120,12 @@
     return nullptr;
 }
 
-status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
+status_t KeyLayoutMap::findScanCodesForKey(
+        int32_t keyCode, std::vector<int32_t>* outScanCodes) const {
     const size_t N = mKeysByScanCode.size();
     for (size_t i=0; i<N; i++) {
         if (mKeysByScanCode.valueAt(i).keyCode == keyCode) {
-            outScanCodes->add(mKeysByScanCode.keyAt(i));
+            outScanCodes->push_back(mKeysByScanCode.keyAt(i));
         }
     }
     return NO_ERROR;
diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp
index 624f152..865366b 100644
--- a/libs/input/VirtualKeyMap.cpp
+++ b/libs/input/VirtualKeyMap.cpp
@@ -112,7 +112,7 @@
                         "width=%d, height=%d",
                         defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height);
 #endif
-                mMap->mVirtualKeys.push(defn);
+                mMap->mVirtualKeys.push_back(defn);
             } while (consumeFieldDelimiterAndSkipWhitespace());
 
             if (!mTokenizer->isEol()) {
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 52fc9d5..9bd3095 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -93,8 +93,66 @@
     outDesc->rfu1 = 0;
 }
 
+int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage,
+        int32_t fence, const ARect* rect, void** outVirtualAddress,
+        int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
+    if (outBytesPerPixel) *outBytesPerPixel = -1;
+    if (outBytesPerStride) *outBytesPerStride = -1;
+
+    if (!buffer) {
+        return BAD_VALUE;
+    }
+
+    if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
+                  AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) {
+        ALOGE("Invalid usage flags passed to AHardwareBuffer_lock; only "
+                "AHARDWAREBUFFER_USAGE_CPU_* flags are allowed");
+        return BAD_VALUE;
+    }
+
+    usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
+    GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+
+    //Mapper implementations before 3.0 will not return bytes per pixel or
+    //bytes per stride information.
+    if (gbuffer->getBufferMapperVersion() == GraphicBufferMapper::Version::GRALLOC_2) {
+        ALOGE("Mapper versions before 3.0 cannot retrieve bytes per pixel and bytes per stride info");
+        return INVALID_OPERATION;
+    }
+
+    if (gbuffer->getLayerCount() > 1) {
+        ALOGE("Buffer with multiple layers passed to AHardwareBuffer_lock; "
+                "only buffers with one layer are allowed");
+        return INVALID_OPERATION;
+    }
+
+    Rect bounds;
+    if (!rect) {
+        bounds.set(Rect(gbuffer->getWidth(), gbuffer->getHeight()));
+    } else {
+        bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
+    }
+    int32_t bytesPerPixel;
+    int32_t bytesPerStride;
+    int result = gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence, &bytesPerPixel, &bytesPerStride);
+
+    // if hardware returns -1 for bytes per pixel or bytes per stride, we fail
+    // and unlock the buffer
+    if (bytesPerPixel == -1 || bytesPerStride == -1) {
+        gbuffer->unlock();
+        return INVALID_OPERATION;
+    }
+
+    if (outBytesPerPixel) *outBytesPerPixel = bytesPerPixel;
+    if (outBytesPerStride) *outBytesPerStride = bytesPerStride;
+    return result;
+}
+
 int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
-        int32_t fence, const ARect* rect, void** outVirtualAddress) {
+                         int32_t fence, const ARect* rect, void** outVirtualAddress) {
+    int32_t bytesPerPixel;
+    int32_t bytesPerStride;
+
     if (!buffer) return BAD_VALUE;
 
     if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
@@ -119,7 +177,7 @@
     } else {
         bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
     }
-    return gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence);
+    return gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence, &bytesPerPixel, &bytesPerStride);
 }
 
 int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage,
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 02c7c1b..da959e3 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -506,6 +506,18 @@
  */
 int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) __INTRODUCED_IN(29);
 
+/**
+ * Lock an AHardwareBuffer for direct CPU access.
+ *
+ * This function is the same as the above lock function, but passes back
+ * additional information about the bytes per pixel and the bytes per stride
+ * of the locked buffer.  If the bytes per pixel or bytes per stride are unknown
+ * or variable, or if the underlying mapper implementation does not support returning
+ * additional information, then this call will fail with INVALID_OPERATION
+ */
+int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage,
+        int32_t fence, const ARect* rect, void** outVirtualAddress,
+        int32_t* outBytesPerPixel, int32_t* outBytesPerStride) __INTRODUCED_IN(29);
 #endif // __ANDROID_API__ >= 29
 
 __END_DECLS
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index a796e97..23a05f3 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -7,6 +7,7 @@
     AHardwareBuffer_getNativeHandle; # vndk
     AHardwareBuffer_isSupported; # introduced=29
     AHardwareBuffer_lock;
+    AHardwareBuffer_lockAndGetInfo; # introduced=29
     AHardwareBuffer_recvHandleFromUnixSocket;
     AHardwareBuffer_release;
     AHardwareBuffer_sendHandleToUnixSocket;
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index f651309..1980f50 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -595,11 +595,7 @@
 }
 
 void GLESRenderEngine::setScissor(const Rect& region) {
-    // Invert y-coordinate to map to GL-space.
-    int32_t canvasHeight = mFboHeight;
-    int32_t glBottom = canvasHeight - region.bottom;
-
-    glScissor(region.left, glBottom, region.getWidth(), region.getHeight());
+    glScissor(region.left, region.top, region.getWidth(), region.getHeight());
     glEnable(GL_SCISSOR_TEST);
 }
 
@@ -719,6 +715,36 @@
     return cropWin;
 }
 
+void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display,
+                                            const LayerSettings& layer, const Mesh& mesh) {
+    // We separate the layer into 3 parts essentially, such that we only turn on blending for the
+    // top rectangle and the bottom rectangle, and turn off blending for the middle rectangle.
+    FloatRect bounds = layer.geometry.roundedCornersCrop;
+    const auto transformMatrix = display.globalTransform * layer.geometry.positionTransform;
+    const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0);
+    const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0);
+    const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate;
+    const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate;
+    bounds = FloatRect(leftTopCoordinateInBuffer[0], leftTopCoordinateInBuffer[1],
+                       rightBottomCoordinateInBuffer[0], rightBottomCoordinateInBuffer[1]);
+    const int32_t radius = ceil(layer.geometry.roundedCornersRadius);
+
+    const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius);
+    setScissor(topRect);
+    drawMesh(mesh);
+    const Rect bottomRect(bounds.left, bounds.bottom - radius, bounds.right, bounds.bottom);
+    setScissor(bottomRect);
+    drawMesh(mesh);
+
+    // The middle part of the layer can turn off blending.
+    const Rect middleRect(bounds.left, bounds.top + radius, bounds.right, bounds.bottom - radius);
+    setScissor(middleRect);
+    mState.cornerRadius = 0.0;
+    disableBlending();
+    drawMesh(mesh);
+    disableScissor();
+}
+
 status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
     ATRACE_CALL();
     GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
@@ -738,8 +764,6 @@
     glBindFramebuffer(GL_FRAMEBUFFER, framebufferName);
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0);
 
-    mFboHeight = glFramebuffer->getBufferHeight();
-
     uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 
     ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
@@ -750,7 +774,6 @@
 
 void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
     ATRACE_CALL();
-    mFboHeight = 0;
 
     // back to main framebuffer
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -917,7 +940,14 @@
             }
             setSourceDataSpace(layer.sourceDataspace);
 
-            drawMesh(mesh);
+            // We only want to do a special handling for rounded corners when having rounded corners
+            // is the only reason it needs to turn on blending, otherwise, we handle it like the
+            // usual way since it needs to turn on blending anyway.
+            if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
+                handleRoundedCorners(display, layer, mesh);
+            } else {
+                drawMesh(mesh);
+            }
 
             // Cleanup if there's a buffer source
             if (layer.source.buffer.buffer != nullptr) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index efb6ef0..8c8f308 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -69,8 +69,6 @@
     void clearWithColor(float red, float green, float blue, float alpha) override;
     void fillRegionWithColor(const Region& region, float red, float green, float blue,
                              float alpha) override;
-    void setScissor(const Rect& region) override;
-    void disableScissor() override;
     void genTextures(size_t count, uint32_t* names) override;
     void deleteTextures(size_t count, uint32_t const* names) override;
     void bindExternalTextureImage(uint32_t texName, const Image& image) override;
@@ -141,6 +139,8 @@
                                        Protection protection);
     static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
                                                    int hwcFormat, Protection protection);
+    void setScissor(const Rect& region);
+    void disableScissor();
     bool waitSync(EGLSyncKHR sync, EGLint flags);
 
     // A data space is considered HDR data space if it has BT2020 color space
@@ -156,6 +156,13 @@
     // coordinates for the mesh.
     FloatRect setupLayerCropping(const LayerSettings& layer, Mesh& mesh);
 
+    // We do a special handling for rounded corners when it's possible to turn off blending
+    // for the majority of the layer. The rounded corners needs to turn on blending such that
+    // we can set the alpha value correctly, however, only the corners need this, and since
+    // blending is an expensive operation, we want to turn off blending when it's not necessary.
+    void handleRoundedCorners(const DisplaySettings& display, const LayerSettings& layer,
+                              const Mesh& mesh);
+
     EGLDisplay mEGLDisplay;
     EGLConfig mEGLConfig;
     EGLContext mEGLContext;
@@ -185,7 +192,6 @@
     bool mInProtectedContext = false;
     // If set to true, then enables tracing flush() and finish() to systrace.
     bool mTraceGpuCompletion = false;
-    int32_t mFboHeight = 0;
     // Maximum size of mFramebufferImageCache. If more images would be cached, then (approximately)
     // the last recently used buffer should be kicked out.
     uint32_t mFramebufferImageCacheSize = 0;
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index 49bdd2a..cd1182c 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -102,14 +102,21 @@
     // Prime for sRGB->P3 conversion
     if (useColorManagement) {
         Key shaderKey;
-        shaderKey.set(Key::BLEND_MASK | Key::TEXTURE_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK |
-                              Key::INPUT_TF_MASK | Key::OUTPUT_TF_MASK,
-                      Key::BLEND_PREMULT | Key::TEXTURE_EXT | Key::OUTPUT_TRANSFORM_MATRIX_ON |
-                              Key::INPUT_TF_SRGB | Key::OUTPUT_TF_SRGB);
-        for (int i = 0; i < 4; i++) {
+        shaderKey.set(Key::BLEND_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK | Key::INPUT_TF_MASK |
+                              Key::OUTPUT_TF_MASK,
+                      Key::BLEND_PREMULT | Key::OUTPUT_TRANSFORM_MATRIX_ON | Key::INPUT_TF_SRGB |
+                              Key::OUTPUT_TF_SRGB);
+        for (int i = 0; i < 16; i++) {
             shaderKey.set(Key::OPACITY_MASK,
                           (i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT);
             shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE);
+
+            // Cache rounded corners
+            shaderKey.set(Key::ROUNDED_CORNERS_MASK,
+                          (i & 4) ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF);
+
+            // Cache texture off option for window transition
+            shaderKey.set(Key::TEXTURE_MASK, (i & 8) ? Key::TEXTURE_EXT : Key::TEXTURE_OFF);
             if (cache.count(shaderKey) == 0) {
                 cache.emplace(shaderKey, generateProgram(shaderKey));
                 shaderCount++;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index ab34274..b211551 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -103,9 +103,6 @@
     virtual void clearWithColor(float red, float green, float blue, float alpha) = 0;
     virtual void fillRegionWithColor(const Region& region, float red, float green, float blue,
                                      float alpha) = 0;
-
-    virtual void setScissor(const Rect& region) = 0;
-    virtual void disableScissor() = 0;
     virtual void genTextures(size_t count, uint32_t* names) = 0;
     virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
     virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index ddf7420..479c7ac 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -48,8 +48,6 @@
     bool waitFence(base::unique_fd fd) override { return waitFence(&fd); };
     MOCK_METHOD4(clearWithColor, void(float, float, float, float));
     MOCK_METHOD5(fillRegionWithColor, void(const Region&, float, float, float, float));
-    MOCK_METHOD1(setScissor, void(const Rect&));
-    MOCK_METHOD0(disableScissor, void());
     MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
     MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
     MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index e521b61..755418e 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -167,6 +167,12 @@
             override_export_include_dirs: ["include_vndk"],
         },
     },
+    header_libs: [
+        "libnativewindow_headers",
+    ],
+    export_header_lib_headers: [
+        "libnativewindow_headers",
+    ],
 }
 
 subdirs = [
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index ed7ccb0b..4ce891e 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -110,7 +110,7 @@
     }
 
     struct sync_file_info* finfo = sync_file_info(mFenceFd);
-    if (finfo == NULL) {
+    if (finfo == nullptr) {
         ALOGE("sync_file_info returned NULL for fd %d", mFenceFd.get());
         return SIGNAL_TIME_INVALID;
     }
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index f800627..3fc6a2d 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -76,7 +76,7 @@
     usage_deprecated = 0;
     usage  = 0;
     layerCount = 0;
-    handle = NULL;
+    handle = nullptr;
 }
 
 // deprecated
@@ -133,6 +133,9 @@
     if (handle) {
         free_handle();
     }
+    for (auto& [callback, context] : mDeathCallbacks) {
+        callback(context, mId);
+    }
 }
 
 void GraphicBuffer::free_handle()
@@ -143,7 +146,7 @@
         GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
         allocator.free(handle);
     }
-    handle = NULL;
+    handle = nullptr;
 }
 
 status_t GraphicBuffer::initCheck() const {
@@ -178,7 +181,7 @@
     if (handle) {
         GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
         allocator.free(handle);
-        handle = 0;
+        handle = nullptr;
     }
     return initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, "[Reallocation]");
 }
@@ -191,6 +194,7 @@
     if (inFormat != format) return true;
     if (inLayerCount != layerCount) return true;
     if ((usage & inUsage) != inUsage) return true;
+    if ((usage & USAGE_PROTECTED) != (inUsage & USAGE_PROTECTED)) return true;
     return false;
 }
 
@@ -371,14 +375,29 @@
 }
 
 size_t GraphicBuffer::getFlattenedSize() const {
+#ifndef LIBUI_IN_VNDK
+    if (mBufferHubBuffer != nullptr) {
+        return 48;
+    }
+#endif
     return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int);
 }
 
 size_t GraphicBuffer::getFdCount() const {
+#ifndef LIBUI_IN_VNDK
+    if (mBufferHubBuffer != nullptr) {
+        return 0;
+    }
+#endif
     return static_cast<size_t>(handle ? mTransportNumFds : 0);
 }
 
 status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
+#ifndef LIBUI_IN_VNDK
+    if (mBufferHubBuffer != nullptr) {
+        return flattenBufferHubBuffer(buffer, size);
+    }
+#endif
     size_t sizeNeeded = GraphicBuffer::getFlattenedSize();
     if (size < sizeNeeded) return NO_MEMORY;
 
@@ -405,7 +424,7 @@
         buf[11] = int32_t(mTransportNumInts);
         memcpy(fds, handle->data, static_cast<size_t>(mTransportNumFds) * sizeof(int));
         memcpy(buf + 13, handle->data + handle->numFds,
-                static_cast<size_t>(mTransportNumInts) * sizeof(int));
+               static_cast<size_t>(mTransportNumInts) * sizeof(int));
     }
 
     buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded);
@@ -414,14 +433,13 @@
         fds += mTransportNumFds;
         count -= static_cast<size_t>(mTransportNumFds);
     }
-
     return NO_ERROR;
 }
 
-status_t GraphicBuffer::unflatten(
-        void const*& buffer, size_t& size, int const*& fds, size_t& count) {
-    if (size < 12 * sizeof(int)) {
-        android_errorWriteLog(0x534e4554, "114223584");
+status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& fds,
+                                  size_t& count) {
+    // Check if size is not smaller than buf[0] is supposed to take.
+    if (size < sizeof(int)) {
         return NO_MEMORY;
     }
 
@@ -436,10 +454,21 @@
     } else if (buf[0] == 'GBFR') {
         // old version, when usage bits were 32-bits
         flattenWordCount = 12;
+    } else if (buf[0] == 'BHBB') { // BufferHub backed buffer.
+#ifndef LIBUI_IN_VNDK
+        return unflattenBufferHubBuffer(buffer, size);
+#else
+        return BAD_TYPE;
+#endif
     } else {
         return BAD_TYPE;
     }
 
+    if (size < 12 * sizeof(int)) {
+        android_errorWriteLog(0x534e4554, "114223584");
+        return NO_MEMORY;
+    }
+
     const size_t numFds  = static_cast<size_t>(buf[10]);
     const size_t numInts = static_cast<size_t>(buf[11]);
 
@@ -452,7 +481,7 @@
         width = height = stride = format = usage_deprecated = 0;
         layerCount = 0;
         usage = 0;
-        handle = NULL;
+        handle = nullptr;
         ALOGE("unflatten: numFds or numInts is too large: %zd, %zd", numFds, numInts);
         return BAD_VALUE;
     }
@@ -480,13 +509,13 @@
         } else {
             usage = uint64_t(usage_deprecated);
         }
-        native_handle* h = native_handle_create(
-                static_cast<int>(numFds), static_cast<int>(numInts));
+        native_handle* h =
+                native_handle_create(static_cast<int>(numFds), static_cast<int>(numInts));
         if (!h) {
             width = height = stride = format = usage_deprecated = 0;
             layerCount = 0;
             usage = 0;
-            handle = NULL;
+            handle = nullptr;
             ALOGE("unflatten: native_handle_create failed");
             return NO_MEMORY;
         }
@@ -497,7 +526,7 @@
         width = height = stride = format = usage_deprecated = 0;
         layerCount = 0;
         usage = 0;
-        handle = NULL;
+        handle = nullptr;
     }
 
     mId = static_cast<uint64_t>(buf[7]) << 32;
@@ -507,7 +536,7 @@
 
     mOwner = ownHandle;
 
-    if (handle != 0) {
+    if (handle != nullptr) {
         buffer_handle_t importedHandle;
         status_t err = mBufferMapper.importBuffer(handle, uint32_t(width), uint32_t(height),
                 uint32_t(layerCount), format, usage, uint32_t(stride), &importedHandle);
@@ -515,7 +544,7 @@
             width = height = stride = format = usage_deprecated = 0;
             layerCount = 0;
             usage = 0;
-            handle = NULL;
+            handle = nullptr;
             ALOGE("unflatten: registerBuffer failed: %s (%d)", strerror(-err), err);
             return err;
         }
@@ -530,11 +559,78 @@
     size -= sizeNeeded;
     fds += numFds;
     count -= numFds;
+    return NO_ERROR;
+}
+
+void GraphicBuffer::addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context) {
+    mDeathCallbacks.emplace_back(deathCallback, context);
+}
+
+#ifndef LIBUI_IN_VNDK
+status_t GraphicBuffer::flattenBufferHubBuffer(void*& buffer, size_t& size) const {
+    sp<NativeHandle> tokenHandle = mBufferHubBuffer->duplicate();
+    if (tokenHandle == nullptr || tokenHandle->handle() == nullptr ||
+        tokenHandle->handle()->numFds != 0) {
+        return BAD_VALUE;
+    }
+
+    // Size needed for one label, one number of ints inside the token, one generation number and
+    // the token itself.
+    int numIntsInToken = tokenHandle->handle()->numInts;
+    const size_t sizeNeeded = static_cast<size_t>(3 + numIntsInToken) * sizeof(int);
+    if (size < sizeNeeded) {
+        ALOGE("%s: needed size %d, given size %d. Not enough memory.", __FUNCTION__,
+              static_cast<int>(sizeNeeded), static_cast<int>(size));
+        return NO_MEMORY;
+    }
+    size -= sizeNeeded;
+
+    int* buf = static_cast<int*>(buffer);
+    buf[0] = 'BHBB';
+    buf[1] = numIntsInToken;
+    memcpy(buf + 2, tokenHandle->handle()->data, static_cast<size_t>(numIntsInToken) * sizeof(int));
+    buf[2 + numIntsInToken] = static_cast<int32_t>(mGenerationNumber);
 
     return NO_ERROR;
 }
 
-#ifndef LIBUI_IN_VNDK
+status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& size) {
+    const int* buf = static_cast<const int*>(buffer);
+    int numIntsInToken = buf[1];
+    // Size needed for one label, one number of ints inside the token, one generation number and
+    // the token itself.
+    const size_t sizeNeeded = static_cast<size_t>(3 + numIntsInToken) * sizeof(int);
+    if (size < sizeNeeded) {
+        ALOGE("%s: needed size %d, given size %d. Not enough memory.", __FUNCTION__,
+              static_cast<int>(sizeNeeded), static_cast<int>(size));
+        return NO_MEMORY;
+    }
+    size -= sizeNeeded;
+    native_handle_t* importToken = native_handle_create(/*numFds=*/0, /*numInts=*/numIntsInToken);
+    memcpy(importToken->data, buf + 2, static_cast<size_t>(buf[1]) * sizeof(int));
+    sp<NativeHandle> importTokenHandle = NativeHandle::create(importToken, /*ownHandle=*/true);
+    std::unique_ptr<BufferHubBuffer> bufferHubBuffer = BufferHubBuffer::import(importTokenHandle);
+    if (bufferHubBuffer == nullptr || bufferHubBuffer.get() == nullptr) {
+        return BAD_VALUE;
+    }
+    // Reconstruct this GraphicBuffer object using the new BufferHubBuffer object.
+    if (handle) {
+        free_handle();
+    }
+    mId = 0;
+    mGenerationNumber = static_cast<uint32_t>(buf[2 + numIntsInToken]);
+    mInitCheck =
+            initWithHandle(bufferHubBuffer->duplicateHandle(), /*method=*/TAKE_UNREGISTERED_HANDLE,
+                           bufferHubBuffer->desc().width, bufferHubBuffer->desc().height,
+                           static_cast<PixelFormat>(bufferHubBuffer->desc().format),
+                           bufferHubBuffer->desc().layers, bufferHubBuffer->desc().usage,
+                           bufferHubBuffer->desc().stride);
+    mBufferId = bufferHubBuffer->id();
+    mBufferHubBuffer.reset(std::move(bufferHubBuffer.get()));
+
+    return NO_ERROR;
+}
+
 bool GraphicBuffer::isBufferHubBuffer() const {
     return mBufferHubBuffer != nullptr;
 }
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 06981c3..25b7247 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -53,6 +53,9 @@
     mMapper = std::make_unique<const Gralloc3Mapper>();
     if (!mMapper->isLoaded()) {
         mMapper = std::make_unique<const Gralloc2Mapper>();
+        mMapperVersion = Version::GRALLOC_2;
+    } else {
+        mMapperVersion = Version::GRALLOC_3;
     }
 
     if (!mMapper->isLoaded()) {
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 3bd3748..224dc2c 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -820,7 +820,7 @@
     }
 
     if (numRects > (UINT32_MAX / sizeof(Rect))) {
-        android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0);
+        android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, nullptr, 0);
         return NO_MEMORY;
     }
 
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index e0c6558..c195342 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -21,9 +21,12 @@
 #include <sys/types.h>
 
 #include <string>
+#include <utility>
+#include <vector>
 
 #include <android/hardware_buffer.h>
 #include <ui/ANativeObjectBase.h>
+#include <ui/GraphicBufferMapper.h>
 #include <ui/PixelFormat.h>
 #include <ui/Rect.h>
 #include <utils/Flattenable.h>
@@ -41,6 +44,8 @@
 
 class GraphicBufferMapper;
 
+using GraphicBufferDeathCallback = std::function<void(void* /*context*/, uint64_t bufferId)>;
+
 // ===========================================================================
 // GraphicBuffer
 // ===========================================================================
@@ -214,6 +219,12 @@
     status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
     status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
 
+    GraphicBufferMapper::Version getBufferMapperVersion() const {
+        return mBufferMapper.getMapperVersion();
+    }
+
+    void addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context);
+
 #ifndef LIBUI_IN_VNDK
     // Returns whether this GraphicBuffer is backed by BufferHubBuffer.
     bool isBufferHubBuffer() const;
@@ -275,7 +286,32 @@
     // IGBP::setGenerationNumber), attempts to attach the buffer will fail.
     uint32_t mGenerationNumber;
 
+    // Send a callback when a GraphicBuffer dies.
+    //
+    // This is used for BufferStateLayer caching. GraphicBuffers are refcounted per process. When
+    // A GraphicBuffer doesn't have any more sp<> in a process, it is destroyed. This causes
+    // problems when trying to implicitcly cache across process boundaries. Ideally, both sides
+    // of the cache would hold onto wp<> references. When an app dropped its sp<>, the GraphicBuffer
+    // would be destroyed. Unfortunately, when SurfaceFlinger has only a wp<> reference to the
+    // GraphicBuffer, it immediately goes out of scope in the SurfaceFlinger process. SurfaceFlinger
+    // must hold onto a sp<> to the buffer. When the GraphicBuffer goes out of scope in the app's
+    // process, the client side cache will get this callback. It erases the buffer from its cache
+    // and informs SurfaceFlinger that it should drop its strong pointer reference to the buffer.
+    std::vector<std::pair<GraphicBufferDeathCallback, void* /*mDeathCallbackContext*/>>
+            mDeathCallbacks;
+
 #ifndef LIBUI_IN_VNDK
+    // Flatten this GraphicBuffer object if backed by BufferHubBuffer.
+    status_t flattenBufferHubBuffer(void*& buffer, size_t& size) const;
+
+    // Unflatten into BufferHubBuffer backed GraphicBuffer.
+    // Unflatten will fail if the original GraphicBuffer object is destructed. For instance, a
+    // GraphicBuffer backed by BufferHubBuffer_1 flatten in process/thread A, transport the token
+    // to process/thread B through a socket, BufferHubBuffer_1 dies and bufferhub invalidated the
+    // token. Race condition occurs between the invalidation of the token in bufferhub process and
+    // process/thread B trying to unflatten and import the buffer with that token.
+    status_t unflattenBufferHubBuffer(void const*& buffer, size_t& size);
+
     // Stores a BufferHubBuffer that handles buffer signaling, identification.
     std::unique_ptr<BufferHubBuffer> mBufferHubBuffer;
 #endif // LIBUI_IN_VNDK
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 77c99cc..2461454 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -41,6 +41,10 @@
 class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
 {
 public:
+    enum Version {
+        GRALLOC_2,
+        GRALLOC_3,
+    };
     static void preloadHal();
     static inline GraphicBufferMapper& get() { return getInstance(); }
 
@@ -85,12 +89,16 @@
         return reinterpret_cast<const GrallocMapper&>(*mMapper);
     }
 
+    Version getMapperVersion() const { return mMapperVersion; }
+
 private:
     friend class Singleton<GraphicBufferMapper>;
 
     GraphicBufferMapper();
 
     std::unique_ptr<const GrallocMapper> mMapper;
+
+    Version mMapperVersion;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index c767ce0..a7c248c 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -74,4 +74,49 @@
     EXPECT_EQ(gb->getBufferId(), b1_id);
 }
 
+TEST_F(GraphicBufferTest, flattenAndUnflatten) {
+    std::unique_ptr<BufferHubBuffer> b1 =
+            BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
+                                    kTestUsage, /*userMetadataSize=*/0);
+    ASSERT_NE(b1, nullptr);
+    sp<GraphicBuffer> gb1(new GraphicBuffer(std::move(b1)));
+    gb1->setGenerationNumber(42);
+
+    size_t flattenedSize = gb1->getFlattenedSize();
+    EXPECT_EQ(flattenedSize, 48);
+    size_t fdCount = gb1->getFdCount();
+    EXPECT_EQ(fdCount, 0);
+
+    int data[flattenedSize];
+    int fds[0];
+
+    // Make copies of needed items since flatten modifies them.
+    size_t flattenedSizeCopy = flattenedSize;
+    size_t fdCountCopy = fdCount;
+    void* dataStart = data;
+    int* fdsStart = fds;
+    status_t err = gb1->flatten(dataStart, flattenedSizeCopy, fdsStart, fdCountCopy);
+    ASSERT_EQ(err, NO_ERROR);
+    EXPECT_EQ(flattenedSizeCopy, 0);
+    EXPECT_EQ(fdCountCopy, 0);
+
+    size_t unflattenSize = flattenedSize;
+    size_t unflattenFdCount = fdCount;
+    const void* unflattenData = static_cast<const void*>(dataStart);
+    const int* unflattenFdData = static_cast<const int*>(fdsStart);
+
+    GraphicBuffer* gb2 = new GraphicBuffer();
+    err = gb2->unflatten(unflattenData, unflattenSize, unflattenFdData, unflattenFdCount);
+    ASSERT_EQ(err, NO_ERROR);
+    EXPECT_TRUE(gb2->isBufferHubBuffer());
+
+    EXPECT_EQ(gb2->getWidth(), kTestWidth);
+    EXPECT_EQ(gb2->getHeight(), kTestHeight);
+    EXPECT_EQ(static_cast<uint32_t>(gb2->getPixelFormat()), kTestFormat);
+    EXPECT_EQ(gb2->getUsage(), kTestUsage);
+    EXPECT_EQ(gb2->getLayerCount(), kTestLayerCount);
+    EXPECT_EQ(gb1->getBufferId(), gb2->getBufferId());
+    EXPECT_EQ(gb2->getGenerationNumber(), 42);
+}
+
 } // namespace android
diff --git a/libs/ui/tools/lutgen.cpp b/libs/ui/tools/lutgen.cpp
index 97b0822..85a1ceb 100644
--- a/libs/ui/tools/lutgen.cpp
+++ b/libs/ui/tools/lutgen.cpp
@@ -85,11 +85,11 @@
 static int handleCommandLineArgments(int argc, char* argv[]) {
     static constexpr const char* OPTSTR = "h:d:s:t:";
     static const struct option OPTIONS[] = {
-            { "help",       no_argument,       0, 'h' },
-            { "dimension",  required_argument, 0, 'd' },
-            { "source",     required_argument, 0, 's' },
-            { "target",     required_argument, 0, 't' },
-            { 0, 0, 0, 0 }  // termination of the option list
+            { "help",       no_argument,       nullptr, 'h' },
+            { "dimension",  required_argument, nullptr, 'd' },
+            { "source",     required_argument, nullptr, 's' },
+            { "target",     required_argument, nullptr, 't' },
+            { nullptr, 0, nullptr, 0 }  // termination of the option list
     };
 
     int opt;
diff --git a/opengl/libs/EGL/GLES_layers.md b/opengl/libs/EGL/GLES_layers.md
new file mode 100644
index 0000000..bfc44db
--- /dev/null
+++ b/opengl/libs/EGL/GLES_layers.md
@@ -0,0 +1,258 @@
+# GLES Layers
+
+## EGL Loader Initialization
+After standard entrypoints have all been populated unmodified, a GLES LayerLoader will be instantiated.  If debug layers are enabled, the LayerLoader will scan specified directories for layers, just like the Vulkan loader does.
+
+If layering is enabled, the loader will search for and enumerate a specified layer list.  The layer list will be specified by colon separated filenames (see [Enabling layers](#Enabling-layers) below).
+
+The layers will be traversed in the order they are specified, so the first layer will be directly below the application.  For each layer, it will track two entrypoints from the layer.  `AndroidGLESLayer_Initialize` and `AndroidGLESLayer_GetProcAddress`.
+```cpp
+typedef void* (*PFNEGLGETNEXTLAYERPROCADDRESSPROC)(void*, const char*);
+void* AndroidGLESLayer_Initialize(void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address))
+```
+
+`AndroidGLESLayer_Initialize` is a new function that provides an identifier for the layer to use (layer_id) and an entrypoint that can be called to look up functions below the layer.  The entrypoint can be used like so:
+```cpp
+const char* func = "eglFoo";
+void* gpa = get_next_layer_proc_address(layer_id, func);
+```
+
+Note that only GLES2+ entrypoints will be provided. If a layer tries to make independent GLES 1.x calls, they will be routed to GLES2+ libraries, which may not behave as expected.  Application calls to 1.x will not be affected.
+
+AndroidGLESLayer_GetProcAddress is a new function designed for this layering system.  It takes the address of the next call in the chain that the layer should call when finished.  If there is only one layer, next will point directly to the driver for most functions.
+```cpp
+void* AndroidGLESLayer_GetProcAddress(const char *funcName, EGLFuncPointer next)
+```
+
+For each layer found, the GLES LayerLoader will call `AndroidGLESLayer_Initialize`, and then walk libEGL’s function lists and call `AndroidGLESLayer_GetProcAddress` for all known functions.   The layer can track that next address with any means it wants.  If the layer does not intercept the function, `AndroidGLESLayer_GetProcAddress` must return the same function address it was passed.  The LayerLoader will then update the function hook list to point to the layer’s entrypoint.
+
+The layers are not required to do anything with the info provided by `AndroidGLESLayer_Initialize` or get_next_layer_proc_address, but providing them makes it easier for existing layers (like GAPID and RenderDoc) to support Android.  That way a layer can look up functions independently (i.e. not wait for calls to `AndroidGLESLayer_GetProcAddress`).  Layers must be sure to use gen_next_layer_proc_address if they look up function calls instead of eglGetProcAddress or they will not get an accurate answer.  eglGetProcAddress must be passed down the chain to the platform.
+
+## Placing layers
+
+Where layers can be found, in order of priority
+ 1. System location for root
+    This requires root access
+    ```bash
+    adb root
+    adb disable-verity
+    adb reboot
+    adb root
+    adb shell setenforce 0
+    adb shell mkdir -p /data/local/debug/gles
+    adb push <layer>.so /data/local/debug/gles/
+    ```
+
+ 2. Application's base directory
+    Target application must be debuggable, or you must have root access:
+     ```bash
+     adb push libGLTrace.so /data/local/tmp
+     adb shell run-as com.android.gl2jni cp /data/local/tmp/libGLTrace.so .
+     adb shell run-as com.android.gl2jni ls | grep libGLTrace
+      libGLTrace.so
+     ```
+
+ 3. External APK
+    Determine the ABI of your target application, then install an APK containing the layers you wish to load:
+    ```bash
+    adb install --abi armeabi-v7a layers.apk
+    ```
+
+ 4. In the target application's APK
+
+## Enabling layers
+
+### Per application
+Note these settings will persist across reboots:
+```bash
+# Enable layers
+adb shell settings put global enable_gpu_debug_layers 1
+
+# Specify target application
+adb shell settings put global gpu_debug_app <package_name>
+
+# Specify layer list (from top to bottom)
+adb shell settings put global gpu_debug_layers_gles <layer1:layer2:layerN>
+
+# Specify a package to search for layers
+adb shell settings put global gpu_debug_layer_app <layer_package>
+```
+To disable the per-app layers:
+```
+adb shell settings delete global enable_gpu_debug_layers
+adb shell settings delete global gpu_debug_app
+adb shell settings delete global gpu_debug_layers_gles
+adb shell settings delete global gpu_debug_layer_app
+```
+
+### Globally
+These will be cleared on reboot:
+```bash
+# This will attempt to load layers for all applications, including native executables
+adb shell setprop debug.gles.layers <layer1:layer2:layerN>
+```
+
+
+## Creating a layer
+
+Layers must expose the following two functions described above:
+```cpp
+AndroidGLESLayer_Initialize
+AndroidGLESLayer_GetProcAddress
+```
+
+For a simple layer that just wants to intercept a handful of functions, a passively initialized layer is the way to go.  It can simply wait for the EGL Loader to initialize the function it cares about.  See below for an example of creating a passive layer.
+
+For more formalized layers that need to fully initialize up front, or layers that needs to look up extensions not known to the EGL loader, active layer initialization is the way to go.  The layer can utilize get_next_layer_proc_address provided by `AndroidGLESLayer_Initialize` to look up a function at any time.  The layer must still respond to `AndroidGLESLayer_GetProcAddress` requests from the loader so the platform knows where to route calls. See below for an example of creating an active layer.
+
+### Example Passive Layer Initialization
+```cpp
+namespace {
+
+std::unordered_map<std::string, EGLFuncPointer> funcMap;
+
+EGLAPI EGLBoolean EGLAPIENTRY glesLayer_eglChooseConfig (
+  EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size,
+  EGLint *num_config) {
+
+  EGLFuncPointer entry = funcMap["eglChooseConfig"];
+
+  typedef EGLBoolean (*PFNEGLCHOOSECONFIGPROC)(
+    EGLDisplay, const EGLint*, EGLConfig*, EGLint, EGLint*);
+
+  PFNEGLCHOOSECONFIGPROC next = reinterpret_cast<PFNEGLCHOOSECONFIGPROC>(entry);
+
+  return next(dpy, attrib_list, configs, config_size, num_config);
+}
+
+EGLAPI EGLFuncPointer EGLAPIENTRY eglGPA(const char* funcName) {
+
+  #define GETPROCADDR(func) if(!strcmp(funcName, #func)) { \
+    return (EGLFuncPointer)glesLayer_##func; }
+
+  GETPROCADDR(eglChooseConfig);
+
+  // Don't return anything for unrecognized functions
+  return nullptr;
+}
+
+EGLAPI void EGLAPIENTRY glesLayer_InitializeLayer(
+  void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address) {
+     // This function is purposefully empty, since this layer does not proactively
+     // look up any entrypoints
+  }
+
+EGLAPI EGLFuncPointer EGLAPIENTRY glesLayer_GetLayerProcAddress(
+  const char* funcName, EGLFuncPointer next) {
+  EGLFuncPointer entry = eglGPA(funcName);
+  if (entry != nullptr) {
+    funcMap[std::string(funcName)] = next;
+    return entry;
+  }
+  return next;
+}
+
+}  // namespace
+
+extern "C" {
+  __attribute((visibility("default"))) EGLAPI void AndroidGLESLayer_Initialize(
+    void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address) {
+    return (void)glesLayer_InitializeLayer(layer_id, get_next_layer_proc_address);
+  }
+  __attribute((visibility("default"))) EGLAPI void* AndroidGLESLayer_GetProcAddres(
+    const char *funcName, EGLFuncPointer next) {
+    return (void*)glesLayer_GetLayerProcAddress(funcName, next);
+  }
+}
+```
+
+### Example Active Layer Initialization
+```cpp
+namespace {
+
+std::unordered_map<std::string, EGLFuncPointer> funcMap;
+
+EGLAPI EGLBoolean EGLAPIENTRY glesLayer_eglChooseConfig (
+  EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size,
+  EGLint *num_config) {
+
+  EGLFuncPointer entry = funcMap["eglChooseConfig"];
+
+  typedef EGLBoolean (*PFNEGLCHOOSECONFIGPROC)(
+    EGLDisplay, const EGLint*, EGLConfig*, EGLint, EGLint*);
+
+  PFNEGLCHOOSECONFIGPROC next = reinterpret_cast<PFNEGLCHOOSECONFIGPROC>(entry);
+
+  return next(dpy, attrib_list, configs, config_size, num_config);
+}
+
+EGLAPI EGLFuncPointer EGLAPIENTRY eglGPA(const char* funcName) {
+
+  #define GETPROCADDR(func) if(!strcmp(funcName, #func)) { \
+    return (EGLFuncPointer)glesLayer_##func; }
+
+  GETPROCADDR(eglChooseConfig);
+
+  // Don't return anything for unrecognized functions
+  return nullptr;
+}
+
+EGLAPI void EGLAPIENTRY glesLayer_InitializeLayer(
+  void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address) {
+
+  // Note: This is where the layer would populate its function map with all the
+  // functions it cares about
+  const char* func = “eglChooseConfig”;
+  funcMap[func] = get_next_layer_proc_address(layer_id, func);
+}
+
+EGLAPI EGLFuncPointer EGLAPIENTRY glesLayer_GetLayerProcAddress(
+  const char* funcName, EGLFuncPointer next) {
+  EGLFuncPointer entry = eglGPA(funcName);
+  if (entry != nullptr) {
+    return entry;
+  }
+
+  return next;
+}
+
+}  // namespace
+
+extern "C" {
+  __attribute((visibility("default"))) EGLAPI void AndroidGLESLayer_Initialize(
+    void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address) {
+    return (void)glesLayer_InitializeLayer(layer_id, get_next_layer_proc_address);
+  }
+  __attribute((visibility("default"))) EGLAPI void* AndroidGLESLayer_GetProcAddres(
+    const char *funcName, EGLFuncPointer next) {
+    return (void*)glesLayer_GetLayerProcAddress(funcName, next);
+  }
+}
+```
+
+## Caveats
+Only supports GLES 2.0+.
+
+When layering is enabled, GLES 1.x exclusive functions will continue to route to GLES 1.x drivers.  But functions shared with GLES 2.0+ (like glGetString) will be routed to 2.0+ drivers, which can cause confusion.
+
+## FAQ
+ - Who can use layers?
+   - GLES Layers can be loaded by any debuggable application, or for any application if you have root access
+ - How do we know if layers are working on a device?
+   - This feature is backed by Android CTS, so you can run `atest CtsGpuToolsHostTestCases`
+ - How does a app determine if this feature is supported?
+   - There are two ways.  First you can check against the version of Android.
+     ```bash
+     # Q is the first that will support this, so look for `Q` or 10 for release
+     adb shell getprop ro.build.version.sdk 
+     # Or look for the SDK version, which should be 29 for Q
+     adb shell getprop ro.build.version.sdk
+     ```
+   - Secondly, if you want to determine from an application that can't call out to ADB for this, you can check for the [EGL_ANDROID_GLES_layers](../../specs/EGL_ANDROID_GLES_layers.txt). It simply indicates support of this layering system:
+     ```cpp
+     std::string display_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+     if (display_extension.find("EGL_ANDROID_GLES_layers") != std::string::npos)
+     {
+        // Layers are supported!
+     }
+     ```
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index c100db7..54fa89f 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -314,6 +314,24 @@
             }
         }
 
+        if (cnx->minor == 5) {
+            // full list in egl_entries.in
+            if (!cnx->egl.eglCreateImage ||
+                !cnx->egl.eglDestroyImage ||
+                !cnx->egl.eglGetPlatformDisplay ||
+                !cnx->egl.eglCreatePlatformWindowSurface ||
+                !cnx->egl.eglCreatePlatformPixmapSurface ||
+                !cnx->egl.eglCreateSync ||
+                !cnx->egl.eglDestroySync ||
+                !cnx->egl.eglClientWaitSync ||
+                !cnx->egl.eglGetSyncAttrib ||
+                !cnx->egl.eglWaitSync) {
+                ALOGE("Driver indicates EGL 1.5 support, but does not have "
+                      "a critical API");
+                cnx->minor = 4;
+            }
+        }
+
         // the query strings are per-display
         mVendorString = sVendorString;
         mVersionString.clear();
diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp
index f936ac0..ac01dc8 100644
--- a/opengl/libs/EGL/egl_layers.cpp
+++ b/opengl/libs/EGL/egl_layers.cpp
@@ -37,9 +37,8 @@
 // 2. If none enabled, check system properties
 //
 // - Layer initializing -
-// TODO: ADD DETAIL ABOUT NEW INTERFACES
-// - InitializeLayer (provided by layer, called by loader)
-// - GetLayerProcAddress (provided by layer, called by loader)
+// - AndroidGLESLayer_Initialize (provided by layer, called by loader)
+// - AndroidGLESLayer_GetProcAddress (provided by layer, called by loader)
 // - getNextLayerProcAddress (provided by loader, called by layer)
 //
 // 1. Walk through defs for egl and each gl version
@@ -73,27 +72,30 @@
 
 const void* getNextLayerProcAddress(void* layer_id, const char* name) {
     // Use layer_id to find funcs for layer below current
-    // This is the same key provided in InitializeLayer
+    // This is the same key provided in AndroidGLESLayer_Initialize
     auto next_layer_funcs = reinterpret_cast<FunctionTable*>(layer_id);
     EGLFuncPointer val;
 
+    ALOGV("getNextLayerProcAddress servicing %s", name);
+
     if (func_indices.find(name) == func_indices.end()) {
         // No entry for this function - it is an extension
         // call down the GPA chain directly to the impl
-        ALOGV("getNextLayerProcAddress servicing %s", name);
+        ALOGV("getNextLayerProcAddress - name(%s) no func_indices entry found", name);
 
         // Look up which GPA we should use
         int gpaIndex = func_indices["eglGetProcAddress"];
+        ALOGV("getNextLayerProcAddress - name(%s) gpaIndex(%i) <- using GPA from this index", name, gpaIndex);
         EGLFuncPointer gpaNext = (*next_layer_funcs)[gpaIndex];
+        ALOGV("getNextLayerProcAddress - name(%s) gpaIndex(%i) gpaNext(%llu) <- using GPA at this address", name, gpaIndex, (unsigned long long)gpaNext);
 
-        ALOGV("Calling down the GPA chain (%llu) for %s", (unsigned long long)gpaNext, name);
 
         // Call it for the requested function
         typedef void* (*PFNEGLGETPROCADDRESSPROC)(const char*);
         PFNEGLGETPROCADDRESSPROC next = reinterpret_cast<PFNEGLGETPROCADDRESSPROC>(gpaNext);
 
         val = reinterpret_cast<EGLFuncPointer>(next(name));
-        ALOGV("Got back %llu for %s", (unsigned long long)val, name);
+        ALOGV("getNextLayerProcAddress - name(%s) gpaIndex(%i) gpaNext(%llu) Got back (%llu) from GPA", name, gpaIndex, (unsigned long long)gpaNext, (unsigned long long)val);
 
         // We should store it now, but to do that, we need to move func_idx to the class so we can
         // increment it separately
@@ -101,10 +103,10 @@
         return reinterpret_cast<void*>(val);
     }
 
-    // int index = func_indices[name];
-    // val = (*next_layer_funcs)[index];
-    // return reinterpret_cast<void*>(val);
-    return reinterpret_cast<void*>((*next_layer_funcs)[func_indices[name]]);
+    int index = func_indices[name];
+    val = (*next_layer_funcs)[index];
+    ALOGV("getNextLayerProcAddress - name(%s) index(%i) entry(%llu) - Got a hit, returning known entry", name, index, (unsigned long long)val);
+    return reinterpret_cast<void*>(val);
 }
 
 void SetupFuncMaps(FunctionTable& functions, char const* const* entries, EGLFuncPointer* curr,
@@ -115,14 +117,20 @@
         // Some names overlap, only fill with initial entry
         // This does mean that some indices will not be used
         if (func_indices.find(name) == func_indices.end()) {
+            ALOGV("SetupFuncMaps - name(%s), func_idx(%i), No entry for func_indices, assigning now", name, func_idx);
             func_names[func_idx] = name;
             func_indices[name] = func_idx;
+        } else {
+            ALOGV("SetupFuncMaps - name(%s), func_idx(%i), Found entry for func_indices", name, func_idx);
         }
 
         // Populate layer_functions once with initial value
         // These values will arrive in priority order, starting with platform entries
         if (functions[func_idx] == nullptr) {
+            ALOGV("SetupFuncMaps - name(%s), func_idx(%i), No entry for functions, assigning (%llu)", name, func_idx, (unsigned long long) *curr);
             functions[func_idx] = *curr;
+        } else {
+            ALOGV("SetupFuncMaps - name(%s), func_idx(%i), Found entry for functions (%llu)", name, func_idx, (unsigned long long) functions[func_idx]);
         }
 
         entries++;
@@ -400,7 +408,7 @@
                 }
 
                 // Find the layer's Initialize function
-                std::string init_func = "InitializeLayer";
+                std::string init_func = "AndroidGLESLayer_Initialize";
                 ALOGV("Looking for entrypoint %s", init_func.c_str());
 
                 layer_init_func LayerInit =
@@ -414,7 +422,7 @@
                 }
 
                 // Find the layer's setup function
-                std::string setup_func = "GetLayerProcAddress";
+                std::string setup_func = "AndroidGLESLayer_GetProcAddress";
                 ALOGV("Looking for entrypoint %s", setup_func.c_str());
 
                 layer_setup_func LayerSetup =
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 872631f..34262f3 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -139,7 +139,8 @@
 char const * const gClientExtensionString =
         "EGL_EXT_client_extensions "
         "EGL_KHR_platform_android "
-        "EGL_ANGLE_platform_angle";
+        "EGL_ANGLE_platform_angle "
+        "EGL_ANDROID_GLES_layers";
 // clang-format on
 
 // extensions not exposed to applications but used by the ANDROID system
diff --git a/opengl/specs/EGL_ANDROID_GLES_layers.txt b/opengl/specs/EGL_ANDROID_GLES_layers.txt
new file mode 100644
index 0000000..eb2a7d9
--- /dev/null
+++ b/opengl/specs/EGL_ANDROID_GLES_layers.txt
@@ -0,0 +1,64 @@
+Name
+
+    ANDROID_GLES_layers
+
+Name Strings
+
+    EGL_ANDROID_GLES_layers
+
+Contributors
+
+    Cody Northrop
+
+Contact
+
+    Cody Northrop, Google LLC (cnorthrop 'at' google.com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, March 3, 2019
+
+Number
+
+    EGL Extension #132
+
+Extension Type
+
+    EGL client extension
+
+Dependencies
+
+    Requires EGL 1.5 or EGL_EXT_client_extensions
+
+Overview
+
+    This extension indicates the EGL loader supports GLES layering on Android.
+    It does not add any requirements to drivers or hardware.
+
+    See frameworks/native/opengl/libs/EGL/GLES_layers.md in Android for
+    more information.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    None
+
+Issues
+
+    None
+
+Revision History
+
+#1 (Cody Northrop, March 3, 2019)
+    - Initial draft.
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 4da1473..0544ec1 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -415,14 +415,14 @@
 
     Device* device = getDeviceLocked(deviceId);
     if (device && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
-        Vector<int32_t> scanCodes;
+        std::vector<int32_t> scanCodes;
         device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
         if (scanCodes.size() != 0) {
             uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)];
             memset(keyState, 0, sizeof(keyState));
             if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) {
                 for (size_t i = 0; i < scanCodes.size(); i++) {
-                    int32_t sc = scanCodes.itemAt(i);
+                    int32_t sc = scanCodes[i];
                     if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, keyState)) {
                         return AKEY_STATE_DOWN;
                     }
@@ -478,7 +478,7 @@
 
     Device* device = getDeviceLocked(deviceId);
     if (device && device->keyMap.haveKeyLayout()) {
-        Vector<int32_t> scanCodes;
+        std::vector<int32_t> scanCodes;
         for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
             scanCodes.clear();
 
@@ -609,13 +609,15 @@
 }
 
 void EventHub::getVirtualKeyDefinitions(int32_t deviceId,
-        Vector<VirtualKeyDefinition>& outVirtualKeys) const {
+        std::vector<VirtualKeyDefinition>& outVirtualKeys) const {
     outVirtualKeys.clear();
 
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device && device->virtualKeyMap) {
-        outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys());
+        const std::vector<VirtualKeyDefinition> virtualKeys =
+                device->virtualKeyMap->getVirtualKeys();
+        outVirtualKeys.insert(outVirtualKeys.end(), virtualKeys.begin(), virtualKeys.end());
     }
 }
 
@@ -1680,11 +1682,11 @@
         return false;
     }
 
-    Vector<int32_t> scanCodes;
+    std::vector<int32_t> scanCodes;
     device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes);
     const size_t N = scanCodes.size();
     for (size_t i=0; i<N && i<=KEY_MAX; i++) {
-        int32_t sc = scanCodes.itemAt(i);
+        int32_t sc = scanCodes[i];
         if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
             return true;
         }
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 44f7b37..63a20ef 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -228,7 +228,7 @@
     virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0;
 
     virtual void getVirtualKeyDefinitions(int32_t deviceId,
-            Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
+            std::vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
 
     virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const = 0;
     virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) = 0;
@@ -304,7 +304,7 @@
     virtual void setLedState(int32_t deviceId, int32_t led, bool on);
 
     virtual void getVirtualKeyDefinitions(int32_t deviceId,
-            Vector<VirtualKeyDefinition>& outVirtualKeys) const;
+            std::vector<VirtualKeyDefinition>& outVirtualKeys) const;
 
     virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const;
     virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index bcb1ec5..0d5bc15 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -524,10 +524,8 @@
 sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
         int32_t x, int32_t y, bool addOutsideTargets, bool addPortalWindows) {
     // Traverse windows from front to back to find touched window.
-    const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
-    size_t numWindows = windowHandles.size();
-    for (size_t i = 0; i < numWindows; i++) {
-        sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
+    const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+    for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
         const InputWindowInfo* windowInfo = windowHandle->getInfo();
         if (windowInfo->displayId == displayId) {
             int32_t flags = windowInfo->layoutParamsFlags;
@@ -859,7 +857,7 @@
     }
 
     // Identify targets.
-    Vector<InputTarget> inputTargets;
+    std::vector<InputTarget> inputTargets;
     int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
             entry, inputTargets, nextWakeupTime);
     if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
@@ -910,7 +908,7 @@
     bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
 
     // Identify targets.
-    Vector<InputTarget> inputTargets;
+    std::vector<InputTarget> inputTargets;
 
     bool conflictingPointerActions = false;
     int32_t injectionResult;
@@ -946,11 +944,11 @@
         ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(entry->displayId);
         if (stateIndex >= 0) {
             const TouchState& state = mTouchStatesByDisplay.valueAt(stateIndex);
-            if (!state.portalWindows.isEmpty()) {
+            if (!state.portalWindows.empty()) {
                 // The event has gone through these portal windows, so we add monitoring targets of
                 // the corresponding displays as well.
                 for (size_t i = 0; i < state.portalWindows.size(); i++) {
-                    const InputWindowInfo* windowInfo = state.portalWindows.itemAt(i)->getInfo();
+                    const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo();
                     addMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId,
                             -windowInfo->frameLeft, -windowInfo->frameTop);
                 }
@@ -1004,7 +1002,7 @@
 }
 
 void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
-        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
+        EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) {
 #if DEBUG_DISPATCH_CYCLE
     ALOGD("dispatchEventToCurrentInputTargets");
 #endif
@@ -1013,9 +1011,7 @@
 
     pokeUserActivityLocked(eventEntry);
 
-    for (size_t i = 0; i < inputTargets.size(); i++) {
-        const InputTarget& inputTarget = inputTargets.itemAt(i);
-
+    for (const InputTarget& inputTarget : inputTargets) {
         ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
         if (connectionIndex >= 0) {
             sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
@@ -1181,7 +1177,7 @@
 }
 
 int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
-        const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
+        const EventEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
     int32_t injectionResult;
     std::string reason;
 
@@ -1244,7 +1240,7 @@
 }
 
 int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
-        const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
+        const MotionEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
         bool* outConflictingPointerActions) {
     enum InjectionPermission {
         INJECTION_PERMISSION_UNKNOWN,
@@ -1460,8 +1456,7 @@
     // is at least one touched foreground window.
     {
         bool haveForegroundWindow = false;
-        for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
-            const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
+        for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {
             if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
                 haveForegroundWindow = true;
                 if (! checkInjectionPermission(touchedWindow.windowHandle,
@@ -1491,8 +1486,7 @@
         sp<InputWindowHandle> foregroundWindowHandle =
                 mTempTouchState.getFirstForegroundWindowHandle();
         const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
-        for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
-            const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
+        for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {
             if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
                 sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
                 if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) {
@@ -1504,8 +1498,7 @@
     }
 
     // Ensure all touched foreground windows are ready for new input.
-    for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
-        const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
+    for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {
         if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
             // Check whether the window is ready for more input.
             std::string reason = checkWindowReadyForMoreInputLocked(currentTime,
@@ -1528,10 +1521,9 @@
         sp<InputWindowHandle> foregroundWindowHandle =
                 mTempTouchState.getFirstForegroundWindowHandle();
         if (foregroundWindowHandle->getInfo()->hasWallpaper) {
-            const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
-            size_t numWindows = windowHandles.size();
-            for (size_t i = 0; i < numWindows; i++) {
-                sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
+            const std::vector<sp<InputWindowHandle>> windowHandles =
+                    getWindowHandlesLocked(displayId);
+            for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
                 const InputWindowInfo* info = windowHandle->getInfo();
                 if (info->displayId == displayId
                         && windowHandle->getInfo()->layoutParamsType
@@ -1549,8 +1541,7 @@
     // Success!  Output targets.
     injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
 
-    for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
-        const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
+    for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {
         addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
                 touchedWindow.pointerIds, inputTargets);
     }
@@ -1613,11 +1604,11 @@
                     uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
 
                     for (size_t i = 0; i < mTempTouchState.windows.size(); ) {
-                        TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i);
+                        TouchedWindow& touchedWindow = mTempTouchState.windows[i];
                         if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {
                             touchedWindow.pointerIds.clearBit(pointerId);
                             if (touchedWindow.pointerIds.isEmpty()) {
-                                mTempTouchState.windows.removeAt(i);
+                                mTempTouchState.windows.erase(mTempTouchState.windows.begin() + i);
                                 continue;
                             }
                         }
@@ -1664,17 +1655,15 @@
 }
 
 void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
-        int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets) {
+        int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) {
     sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());
     if (inputChannel == nullptr) {
         ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
         return;
     }
 
-    inputTargets.push();
-
     const InputWindowInfo* windowInfo = windowHandle->getInfo();
-    InputTarget& target = inputTargets.editTop();
+    InputTarget target;
     target.inputChannel = inputChannel;
     target.flags = targetFlags;
     target.xOffset = - windowInfo->frameLeft;
@@ -1683,26 +1672,26 @@
     target.windowXScale = windowInfo->windowXScale;
     target.windowYScale = windowInfo->windowYScale;
     target.pointerIds = pointerIds;
+    inputTargets.push_back(target);
 }
 
-void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets,
+void InputDispatcher::addMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets,
         int32_t displayId, float xOffset, float yOffset) {
-    std::unordered_map<int32_t, Vector<sp<InputChannel>>>::const_iterator it =
+    std::unordered_map<int32_t, std::vector<sp<InputChannel>>>::const_iterator it =
             mMonitoringChannelsByDisplay.find(displayId);
 
     if (it != mMonitoringChannelsByDisplay.end()) {
-        const Vector<sp<InputChannel>>& monitoringChannels = it->second;
+        const std::vector<sp<InputChannel>>& monitoringChannels = it->second;
         const size_t numChannels = monitoringChannels.size();
         for (size_t i = 0; i < numChannels; i++) {
-            inputTargets.push();
-
-            InputTarget& target = inputTargets.editTop();
+            InputTarget target;
             target.inputChannel = monitoringChannels[i];
             target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
             target.xOffset = xOffset;
             target.yOffset = yOffset;
             target.pointerIds.clear();
             target.globalScaleFactor = 1.0f;
+            inputTargets.push_back(target);
         }
     } else {
         // If there is no monitor channel registered or all monitor channel unregistered,
@@ -1735,10 +1724,8 @@
 bool InputDispatcher::isWindowObscuredAtPointLocked(
         const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
     int32_t displayId = windowHandle->getInfo()->displayId;
-    const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
-    size_t numWindows = windowHandles.size();
-    for (size_t i = 0; i < numWindows; i++) {
-        sp<InputWindowHandle> otherHandle = windowHandles.itemAt(i);
+    const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+    for (const sp<InputWindowHandle>& otherHandle : windowHandles) {
         if (otherHandle == windowHandle) {
             break;
         }
@@ -1756,11 +1743,9 @@
 
 bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const {
     int32_t displayId = windowHandle->getInfo()->displayId;
-    const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+    const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
     const InputWindowInfo* windowInfo = windowHandle->getInfo();
-    size_t numWindows = windowHandles.size();
-    for (size_t i = 0; i < numWindows; i++) {
-        sp<InputWindowHandle> otherHandle = windowHandles.itemAt(i);
+    for (const sp<InputWindowHandle>& otherHandle : windowHandles) {
         if (otherHandle == windowHandle) {
             break;
         }
@@ -1973,17 +1958,17 @@
     bool wasEmpty = connection->outboundQueue.isEmpty();
 
     // Enqueue dispatch entries for the requested modes.
-    enqueueDispatchEntry(connection, eventEntry, inputTarget,
+    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
             InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
-    enqueueDispatchEntry(connection, eventEntry, inputTarget,
+    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
             InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
-    enqueueDispatchEntry(connection, eventEntry, inputTarget,
+    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
             InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
-    enqueueDispatchEntry(connection, eventEntry, inputTarget,
+    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
             InputTarget::FLAG_DISPATCH_AS_IS);
-    enqueueDispatchEntry(connection, eventEntry, inputTarget,
+    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
             InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
-    enqueueDispatchEntry(connection, eventEntry, inputTarget,
+    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
             InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
 
     // If the outbound queue was previously empty, start the dispatch cycle going.
@@ -1992,7 +1977,7 @@
     }
 }
 
-void InputDispatcher::enqueueDispatchEntry(
+void InputDispatcher::enqueueDispatchEntryLocked(
         const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
         int32_t dispatchMode) {
     int32_t inputTargetFlags = inputTarget->flags;
@@ -2069,6 +2054,10 @@
             delete dispatchEntry;
             return; // skip the inconsistent event
         }
+
+        dispatchPointerDownOutsideFocusIfNecessary(motionEntry->source,
+                dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken());
+
         break;
     }
     }
@@ -2081,6 +2070,32 @@
     // Enqueue the dispatch entry.
     connection->outboundQueue.enqueueAtTail(dispatchEntry);
     traceOutboundQueueLength(connection);
+
+}
+
+void InputDispatcher::dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action,
+        const sp<IBinder>& newToken) {
+    int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
+    if (source != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) {
+        return;
+    }
+
+    sp<InputWindowHandle> inputWindowHandle = getWindowHandleLocked(newToken);
+    if (inputWindowHandle == nullptr) {
+        return;
+    }
+
+    int32_t displayId = inputWindowHandle->getInfo()->displayId;
+    sp<InputWindowHandle> focusedWindowHandle =
+            getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+
+    bool hasFocusChanged = !focusedWindowHandle || focusedWindowHandle->getToken() != newToken;
+
+    if (!hasFocusChanged) {
+        return;
+    }
+
+    // Dispatch onPointerDownOutsideFocus to the policy.
 }
 
 void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -2333,7 +2348,7 @@
 void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked (
         const CancelationOptions& options) {
     for (auto& it : mMonitoringChannelsByDisplay) {
-        const Vector<sp<InputChannel>>& monitoringChannels = it.second;
+        const std::vector<sp<InputChannel>>& monitoringChannels = it.second;
         const size_t numChannels = monitoringChannels.size();
         for (size_t i = 0; i < numChannels; i++) {
             synthesizeCancelationEventsForInputChannelLocked(monitoringChannels[i], options);
@@ -2358,11 +2373,11 @@
 
     nsecs_t currentTime = now();
 
-    Vector<EventEntry*> cancelationEvents;
+    std::vector<EventEntry*> cancelationEvents;
     connection->inputState.synthesizeCancelationEvents(currentTime,
             cancelationEvents, options);
 
-    if (!cancelationEvents.isEmpty()) {
+    if (!cancelationEvents.empty()) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
         ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
                 "with reality: %s, mode=%d.",
@@ -2370,7 +2385,7 @@
                 options.reason, options.mode);
 #endif
         for (size_t i = 0; i < cancelationEvents.size(); i++) {
-            EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i);
+            EventEntry* cancelationEventEntry = cancelationEvents[i];
             switch (cancelationEventEntry->type) {
             case EventEntry::TYPE_KEY:
                 logOutboundKeyDetails("cancel - ",
@@ -2400,7 +2415,7 @@
             target.inputChannel = connection->inputChannel;
             target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
 
-            enqueueDispatchEntry(connection, cancelationEventEntry, // increments ref
+            enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
                     &target, InputTarget::FLAG_DISPATCH_AS_IS);
 
             cancelationEventEntry->release();
@@ -3011,24 +3026,23 @@
     }
 }
 
-Vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(int32_t displayId) const {
-    std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>>::const_iterator it =
+std::vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(
+        int32_t displayId) const {
+    std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>::const_iterator it =
             mWindowHandlesByDisplay.find(displayId);
     if(it != mWindowHandlesByDisplay.end()) {
         return it->second;
     }
 
     // Return an empty one if nothing found.
-    return Vector<sp<InputWindowHandle>>();
+    return std::vector<sp<InputWindowHandle>>();
 }
 
 sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
         const sp<IBinder>& windowHandleToken) const {
     for (auto& it : mWindowHandlesByDisplay) {
-        const Vector<sp<InputWindowHandle>> windowHandles = it.second;
-        size_t numWindows = windowHandles.size();
-        for (size_t i = 0; i < numWindows; i++) {
-            const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+        const std::vector<sp<InputWindowHandle>> windowHandles = it.second;
+        for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
             if (windowHandle->getToken() == windowHandleToken) {
                 return windowHandle;
             }
@@ -3039,11 +3053,9 @@
 
 bool InputDispatcher::hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const {
     for (auto& it : mWindowHandlesByDisplay) {
-        const Vector<sp<InputWindowHandle>> windowHandles = it.second;
-        size_t numWindows = windowHandles.size();
-        for (size_t i = 0; i < numWindows; i++) {
-            if (windowHandles.itemAt(i)->getToken()
-                    == windowHandle->getToken()) {
+        const std::vector<sp<InputWindowHandle>> windowHandles = it.second;
+        for (const sp<InputWindowHandle>& handle : windowHandles) {
+            if (handle->getToken() == windowHandle->getToken()) {
                 if (windowHandle->getInfo()->displayId != it.first) {
                     ALOGE("Found window %s in display %" PRId32
                             ", but it should belong to display %" PRId32,
@@ -3072,7 +3084,7 @@
  * For focused handle, check if need to change and send a cancel event to previous one.
  * For removed handle, check if need to send a cancel event if already in touch.
  */
-void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& inputWindowHandles,
+void InputDispatcher::setInputWindows(const std::vector<sp<InputWindowHandle>>& inputWindowHandles,
         int32_t displayId, const sp<ISetInputWindowsListener>& setInputWindowsListener) {
 #if DEBUG_FOCUS
     ALOGD("setInputWindows displayId=%" PRId32, displayId);
@@ -3081,28 +3093,27 @@
         std::scoped_lock _l(mLock);
 
         // Copy old handles for release if they are no longer present.
-        const Vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
+        const std::vector<sp<InputWindowHandle>> oldWindowHandles =
+                getWindowHandlesLocked(displayId);
 
         sp<InputWindowHandle> newFocusedWindowHandle = nullptr;
         bool foundHoveredWindow = false;
 
-        if (inputWindowHandles.isEmpty()) {
+        if (inputWindowHandles.empty()) {
             // Remove all handles on a display if there are no windows left.
             mWindowHandlesByDisplay.erase(displayId);
         } else {
             // Since we compare the pointer of input window handles across window updates, we need
             // to make sure the handle object for the same window stays unchanged across updates.
-            const Vector<sp<InputWindowHandle>>& oldHandles = mWindowHandlesByDisplay[displayId];
+            const std::vector<sp<InputWindowHandle>>& oldHandles =
+                    mWindowHandlesByDisplay[displayId];
             std::unordered_map<sp<IBinder>, sp<InputWindowHandle>, IBinderHash> oldHandlesByTokens;
-            for (size_t i = 0; i < oldHandles.size(); i++) {
-                const sp<InputWindowHandle>& handle = oldHandles.itemAt(i);
+            for (const sp<InputWindowHandle>& handle : oldHandles) {
                 oldHandlesByTokens[handle->getToken()] = handle;
             }
 
-            const size_t numWindows = inputWindowHandles.size();
-            Vector<sp<InputWindowHandle>> newHandles;
-            for (size_t i = 0; i < numWindows; i++) {
-                const sp<InputWindowHandle>& handle = inputWindowHandles.itemAt(i);
+            std::vector<sp<InputWindowHandle>> newHandles;
+            for (const sp<InputWindowHandle>& handle : inputWindowHandles) {
                 if (!handle->updateInfo() || (getInputChannelLocked(handle->getToken()) == nullptr
                         && handle->getInfo()->portalToDisplayId == ADISPLAY_ID_NONE)) {
                     ALOGE("Window handle %s has no registered input channel",
@@ -3127,8 +3138,7 @@
                 }
             }
 
-            for (size_t i = 0; i < newHandles.size(); i++) {
-                const sp<InputWindowHandle>& windowHandle = newHandles.itemAt(i);
+            for (const sp<InputWindowHandle>& windowHandle : newHandles) {
                 // Set newFocusedWindowHandle to the top most focused window instead of the last one
                 if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus
                         && windowHandle->getInfo()->visible) {
@@ -3184,7 +3194,7 @@
         if (stateIndex >= 0) {
             TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex);
             for (size_t i = 0; i < state.windows.size(); ) {
-                TouchedWindow& touchedWindow = state.windows.editItemAt(i);
+                TouchedWindow& touchedWindow = state.windows[i];
                 if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
 #if DEBUG_FOCUS
                     ALOGD("Touched window was removed: %s in display %" PRId32,
@@ -3198,7 +3208,7 @@
                         synthesizeCancelationEventsForInputChannelLocked(
                                 touchedInputChannel, options);
                     }
-                    state.windows.removeAt(i);
+                    state.windows.erase(state.windows.begin() + i);
                 } else {
                   ++i;
                 }
@@ -3209,9 +3219,7 @@
         // This ensures that unused input channels are released promptly.
         // Otherwise, they might stick around until the window handle is destroyed
         // which might not happen until the next GC.
-        size_t numWindows = oldWindowHandles.size();
-        for (size_t i = 0; i < numWindows; i++) {
-            const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i);
+        for (const sp<InputWindowHandle>& oldWindowHandle : oldWindowHandles) {
             if (!hasWindowHandleLocked(oldWindowHandle)) {
 #if DEBUG_FOCUS
                 ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
@@ -3243,13 +3251,11 @@
             if (oldFocusedApplicationHandle != inputApplicationHandle) {
                 if (oldFocusedApplicationHandle != nullptr) {
                     resetANRTimeoutsLocked();
-                    oldFocusedApplicationHandle->releaseInfo();
                 }
                 mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
             }
         } else if (oldFocusedApplicationHandle != nullptr) {
             resetANRTimeoutsLocked();
-            oldFocusedApplicationHandle->releaseInfo();
             oldFocusedApplicationHandle.clear();
             mFocusedApplicationHandlesByDisplay.erase(displayId);
         }
@@ -3415,7 +3421,7 @@
                     int32_t oldTargetFlags = touchedWindow.targetFlags;
                     BitSet32 pointerIds = touchedWindow.pointerIds;
 
-                    state.windows.removeAt(i);
+                    state.windows.erase(state.windows.begin() + i);
 
                     int32_t newTargetFlags = oldTargetFlags
                             & (InputTarget::FLAG_FOREGROUND
@@ -3531,7 +3537,7 @@
             dump += StringPrintf(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n",
                     state.displayId, toString(state.down), toString(state.split),
                     state.deviceId, state.source);
-            if (!state.windows.isEmpty()) {
+            if (!state.windows.empty()) {
                 dump += INDENT3 "Windows:\n";
                 for (size_t i = 0; i < state.windows.size(); i++) {
                     const TouchedWindow& touchedWindow = state.windows[i];
@@ -3543,10 +3549,10 @@
             } else {
                 dump += INDENT3 "Windows: <none>\n";
             }
-            if (!state.portalWindows.isEmpty()) {
+            if (!state.portalWindows.empty()) {
                 dump += INDENT3 "Portal windows:\n";
                 for (size_t i = 0; i < state.portalWindows.size(); i++) {
-                    const sp<InputWindowHandle> portalWindowHandle = state.portalWindows.itemAt(i);
+                    const sp<InputWindowHandle> portalWindowHandle = state.portalWindows[i];
                     dump += StringPrintf(INDENT4 "%zu: name='%s'\n",
                             i, portalWindowHandle->getName().c_str());
                 }
@@ -3558,12 +3564,12 @@
 
     if (!mWindowHandlesByDisplay.empty()) {
        for (auto& it : mWindowHandlesByDisplay) {
-            const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+            const std::vector<sp<InputWindowHandle>> windowHandles = it.second;
             dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first);
-            if (!windowHandles.isEmpty()) {
+            if (!windowHandles.empty()) {
                 dump += INDENT2 "Windows:\n";
                 for (size_t i = 0; i < windowHandles.size(); i++) {
-                    const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+                    const sp<InputWindowHandle>& windowHandle = windowHandles[i];
                     const InputWindowInfo* windowInfo = windowHandle->getInfo();
 
                     dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
@@ -3600,7 +3606,7 @@
 
     if (!mMonitoringChannelsByDisplay.empty()) {
        for (auto& it : mMonitoringChannelsByDisplay) {
-            const Vector<sp<InputChannel>>& monitoringChannels = it.second;
+            const std::vector<sp<InputChannel>>& monitoringChannels = it.second;
             dump += StringPrintf(INDENT "MonitoringChannels in display %" PRId32 ":\n", it.first);
             const size_t numChannels = monitoringChannels.size();
             for (size_t i = 0; i < numChannels; i++) {
@@ -3754,9 +3760,9 @@
 
         // Store monitor channel by displayId.
         if (monitor) {
-            Vector<sp<InputChannel>>& monitoringChannels =
+            std::vector<sp<InputChannel>>& monitoringChannels =
                     mMonitoringChannelsByDisplay[displayId];
-            monitoringChannels.push(inputChannel);
+            monitoringChannels.push_back(inputChannel);
         }
 
         mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
@@ -3817,11 +3823,11 @@
 void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) {
     for (auto it = mMonitoringChannelsByDisplay.begin();
             it != mMonitoringChannelsByDisplay.end(); ) {
-        Vector<sp<InputChannel>>& monitoringChannels = it->second;
+        std::vector<sp<InputChannel>>& monitoringChannels = it->second;
         const size_t numChannels = monitoringChannels.size();
         for (size_t i = 0; i < numChannels; i++) {
              if (monitoringChannels[i] == inputChannel) {
-                 monitoringChannels.removeAt(i);
+                 monitoringChannels.erase(monitoringChannels.begin() + i);
                  break;
              }
         }
@@ -4495,13 +4501,12 @@
 }
 
 bool InputDispatcher::InputState::isNeutral() const {
-    return mKeyMementos.isEmpty() && mMotionMementos.isEmpty();
+    return mKeyMementos.empty() && mMotionMementos.empty();
 }
 
 bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source,
         int32_t displayId) const {
-    for (size_t i = 0; i < mMotionMementos.size(); i++) {
-        const MotionMemento& memento = mMotionMementos.itemAt(i);
+    for (const MotionMemento& memento : mMotionMementos) {
         if (memento.deviceId == deviceId
                 && memento.source == source
                 && memento.displayId == displayId
@@ -4527,7 +4532,7 @@
         }
         ssize_t index = findKeyMemento(entry);
         if (index >= 0) {
-            mKeyMementos.removeAt(index);
+            mKeyMementos.erase(mKeyMementos.begin() + index);
             return true;
         }
         /* FIXME: We can't just drop the key up event because that prevents creating
@@ -4552,7 +4557,7 @@
     case AKEY_EVENT_ACTION_DOWN: {
         ssize_t index = findKeyMemento(entry);
         if (index >= 0) {
-            mKeyMementos.removeAt(index);
+            mKeyMementos.erase(mKeyMementos.begin() + index);
         }
         addKeyMemento(entry, flags);
         return true;
@@ -4571,7 +4576,7 @@
     case AMOTION_EVENT_ACTION_CANCEL: {
         ssize_t index = findMotionMemento(entry, false /*hovering*/);
         if (index >= 0) {
-            mMotionMementos.removeAt(index);
+            mMotionMementos.erase(mMotionMementos.begin() + index);
             return true;
         }
 #if DEBUG_OUTBOUND_EVENT_DETAILS
@@ -4585,7 +4590,7 @@
     case AMOTION_EVENT_ACTION_DOWN: {
         ssize_t index = findMotionMemento(entry, false /*hovering*/);
         if (index >= 0) {
-            mMotionMementos.removeAt(index);
+            mMotionMementos.erase(mMotionMementos.begin() + index);
         }
         addMotionMemento(entry, flags, false /*hovering*/);
         return true;
@@ -4610,9 +4615,9 @@
             // anything generating fallback events (e.g. DPad keys for joystick movements).
             if (index >= 0) {
                 if (entry->pointerCoords[0].isEmpty()) {
-                    mMotionMementos.removeAt(index);
+                    mMotionMementos.erase(mMotionMementos.begin() + index);
                 } else {
-                    MotionMemento& memento = mMotionMementos.editItemAt(index);
+                    MotionMemento& memento = mMotionMementos[index];
                     memento.setPointers(entry);
                 }
             } else if (!entry->pointerCoords[0].isEmpty()) {
@@ -4623,7 +4628,7 @@
             return true;
         }
         if (index >= 0) {
-            MotionMemento& memento = mMotionMementos.editItemAt(index);
+            MotionMemento& memento = mMotionMementos[index];
             memento.setPointers(entry);
             return true;
         }
@@ -4638,7 +4643,7 @@
     case AMOTION_EVENT_ACTION_HOVER_EXIT: {
         ssize_t index = findMotionMemento(entry, true /*hovering*/);
         if (index >= 0) {
-            mMotionMementos.removeAt(index);
+            mMotionMementos.erase(mMotionMementos.begin() + index);
             return true;
         }
 #if DEBUG_OUTBOUND_EVENT_DETAILS
@@ -4653,7 +4658,7 @@
     case AMOTION_EVENT_ACTION_HOVER_MOVE: {
         ssize_t index = findMotionMemento(entry, true /*hovering*/);
         if (index >= 0) {
-            mMotionMementos.removeAt(index);
+            mMotionMementos.erase(mMotionMementos.begin() + index);
         }
         addMotionMemento(entry, flags, true /*hovering*/);
         return true;
@@ -4666,7 +4671,7 @@
 
 ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const {
     for (size_t i = 0; i < mKeyMementos.size(); i++) {
-        const KeyMemento& memento = mKeyMementos.itemAt(i);
+        const KeyMemento& memento = mKeyMementos[i];
         if (memento.deviceId == entry->deviceId
                 && memento.source == entry->source
                 && memento.displayId == entry->displayId
@@ -4681,7 +4686,7 @@
 ssize_t InputDispatcher::InputState::findMotionMemento(const MotionEntry* entry,
         bool hovering) const {
     for (size_t i = 0; i < mMotionMementos.size(); i++) {
-        const MotionMemento& memento = mMotionMementos.itemAt(i);
+        const MotionMemento& memento = mMotionMementos[i];
         if (memento.deviceId == entry->deviceId
                 && memento.source == entry->source
                 && memento.displayId == entry->displayId
@@ -4693,8 +4698,7 @@
 }
 
 void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) {
-    mKeyMementos.push();
-    KeyMemento& memento = mKeyMementos.editTop();
+    KeyMemento memento;
     memento.deviceId = entry->deviceId;
     memento.source = entry->source;
     memento.displayId = entry->displayId;
@@ -4704,12 +4708,12 @@
     memento.flags = flags;
     memento.downTime = entry->downTime;
     memento.policyFlags = entry->policyFlags;
+    mKeyMementos.push_back(memento);
 }
 
 void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry,
         int32_t flags, bool hovering) {
-    mMotionMementos.push();
-    MotionMemento& memento = mMotionMementos.editTop();
+    MotionMemento memento;
     memento.deviceId = entry->deviceId;
     memento.source = entry->source;
     memento.displayId = entry->displayId;
@@ -4720,6 +4724,7 @@
     memento.setPointers(entry);
     memento.hovering = hovering;
     memento.policyFlags = entry->policyFlags;
+    mMotionMementos.push_back(memento);
 }
 
 void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) {
@@ -4731,23 +4736,21 @@
 }
 
 void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime,
-        Vector<EventEntry*>& outEvents, const CancelationOptions& options) {
-    for (size_t i = 0; i < mKeyMementos.size(); i++) {
-        const KeyMemento& memento = mKeyMementos.itemAt(i);
+        std::vector<EventEntry*>& outEvents, const CancelationOptions& options) {
+    for (KeyMemento& memento : mKeyMementos) {
         if (shouldCancelKey(memento, options)) {
-            outEvents.push(new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
+            outEvents.push_back(new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
                     memento.deviceId, memento.source, memento.displayId, memento.policyFlags,
                     AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED,
                     memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime));
         }
     }
 
-    for (size_t i = 0; i < mMotionMementos.size(); i++) {
-        const MotionMemento& memento = mMotionMementos.itemAt(i);
+    for (const MotionMemento& memento : mMotionMementos) {
         if (shouldCancelMotion(memento, options)) {
             const int32_t action = memento.hovering ?
                     AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL;
-            outEvents.push(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
+            outEvents.push_back(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
                     memento.deviceId, memento.source, memento.displayId, memento.policyFlags,
                     action, 0 /*actionButton*/, memento.flags, AMETA_NONE, 0 /*buttonState*/,
                     MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
@@ -4766,19 +4769,19 @@
 
 void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
     for (size_t i = 0; i < mMotionMementos.size(); i++) {
-        const MotionMemento& memento = mMotionMementos.itemAt(i);
+        const MotionMemento& memento = mMotionMementos[i];
         if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
             for (size_t j = 0; j < other.mMotionMementos.size(); ) {
-                const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j);
+                const MotionMemento& otherMemento = other.mMotionMementos[j];
                 if (memento.deviceId == otherMemento.deviceId
                         && memento.source == otherMemento.source
                         && memento.displayId == otherMemento.displayId) {
-                    other.mMotionMementos.removeAt(j);
+                    other.mMotionMementos.erase(other.mMotionMementos.begin() + j);
                 } else {
                     j += 1;
                 }
             }
-            other.mMotionMementos.push(memento);
+            other.mMotionMementos.push_back(memento);
         }
     }
 }
@@ -4940,7 +4943,7 @@
     }
 
     for (size_t i = 0; i < windows.size(); i++) {
-        TouchedWindow& touchedWindow = windows.editItemAt(i);
+        TouchedWindow& touchedWindow = windows[i];
         if (touchedWindow.windowHandle == windowHandle) {
             touchedWindow.targetFlags |= targetFlags;
             if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
@@ -4951,19 +4954,17 @@
         }
     }
 
-    windows.push();
-
-    TouchedWindow& touchedWindow = windows.editTop();
+    TouchedWindow touchedWindow;
     touchedWindow.windowHandle = windowHandle;
     touchedWindow.targetFlags = targetFlags;
     touchedWindow.pointerIds = pointerIds;
+    windows.push_back(touchedWindow);
 }
 
 void InputDispatcher::TouchState::addPortalWindow(const sp<InputWindowHandle>& windowHandle) {
     size_t numWindows = portalWindows.size();
     for (size_t i = 0; i < numWindows; i++) {
-        sp<InputWindowHandle> portalWindowHandle = portalWindows.itemAt(i);
-        if (portalWindowHandle == windowHandle) {
+        if (portalWindows[i] == windowHandle) {
             return;
         }
     }
@@ -4972,8 +4973,8 @@
 
 void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) {
     for (size_t i = 0; i < windows.size(); i++) {
-        if (windows.itemAt(i).windowHandle == windowHandle) {
-            windows.removeAt(i);
+        if (windows[i].windowHandle == windowHandle) {
+            windows.erase(windows.begin() + i);
             return;
         }
     }
@@ -4981,8 +4982,8 @@
 
 void InputDispatcher::TouchState::removeWindowByToken(const sp<IBinder>& token) {
     for (size_t i = 0; i < windows.size(); i++) {
-        if (windows.itemAt(i).windowHandle->getToken() == token) {
-            windows.removeAt(i);
+        if (windows[i].windowHandle->getToken() == token) {
+            windows.erase(windows.begin() + i);
             return;
         }
     }
@@ -4990,21 +4991,21 @@
 
 void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
     for (size_t i = 0 ; i < windows.size(); ) {
-        TouchedWindow& window = windows.editItemAt(i);
+        TouchedWindow& window = windows[i];
         if (window.targetFlags & (InputTarget::FLAG_DISPATCH_AS_IS
                 | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) {
             window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK;
             window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS;
             i += 1;
         } else {
-            windows.removeAt(i);
+            windows.erase(windows.begin() + i);
         }
     }
 }
 
 sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const {
     for (size_t i = 0; i < windows.size(); i++) {
-        const TouchedWindow& window = windows.itemAt(i);
+        const TouchedWindow& window = windows[i];
         if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
             return window.windowHandle;
         }
@@ -5015,8 +5016,7 @@
 bool InputDispatcher::TouchState::isSlippery() const {
     // Must have exactly one foreground window.
     bool haveSlipperyForegroundWindow = false;
-    for (size_t i = 0; i < windows.size(); i++) {
-        const TouchedWindow& window = windows.itemAt(i);
+    for (const TouchedWindow& window : windows) {
         if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
             if (haveSlipperyForegroundWindow
                     || !(window.windowHandle->getInfo()->layoutParamsFlags
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 24ae32f..3735a0b 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -23,8 +23,6 @@
 #include <input/InputTransport.h>
 #include <input/InputWindow.h>
 #include <input/ISetInputWindowsListener.h>
-#include <utils/KeyedVector.h>
-#include <utils/Vector.h>
 #include <utils/threads.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
@@ -315,7 +313,7 @@
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
+    virtual void setInputWindows(const std::vector<sp<InputWindowHandle> >& inputWindowHandles,
             int32_t displayId,
             const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) = 0;
 
@@ -407,7 +405,7 @@
             int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
             uint32_t policyFlags);
 
-    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
+    virtual void setInputWindows(const std::vector<sp<InputWindowHandle> >& inputWindowHandles,
             int32_t displayId,
             const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr);
     virtual void setFocusedApplication(int32_t displayId,
@@ -762,7 +760,7 @@
 
         // Synthesizes cancelation events for the current state and resets the tracked state.
         void synthesizeCancelationEvents(nsecs_t currentTime,
-                Vector<EventEntry*>& outEvents, const CancelationOptions& options);
+                std::vector<EventEntry*>& outEvents, const CancelationOptions& options);
 
         // Clears the current state.
         void clear();
@@ -815,8 +813,8 @@
             void setPointers(const MotionEntry* entry);
         };
 
-        Vector<KeyMemento> mKeyMementos;
-        Vector<MotionMemento> mMotionMementos;
+        std::vector<KeyMemento> mKeyMementos;
+        std::vector<MotionMemento> mMotionMementos;
         KeyedVector<int32_t, int32_t> mFallbackKeys;
 
         ssize_t findKeyMemento(const KeyEntry* entry) const;
@@ -941,7 +939,7 @@
     ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock);
 
     // Input channels that will receive a copy of all input events sent to the provided display.
-    std::unordered_map<int32_t, Vector<sp<InputChannel>>> mMonitoringChannelsByDisplay
+    std::unordered_map<int32_t, std::vector<sp<InputChannel>>> mMonitoringChannelsByDisplay
             GUARDED_BY(mLock);
 
     // Event injection and synchronization.
@@ -998,10 +996,11 @@
     bool mDispatchFrozen GUARDED_BY(mLock);
     bool mInputFilterEnabled GUARDED_BY(mLock);
 
-    std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay
+    std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay
             GUARDED_BY(mLock);
     // Get window handles by display, return an empty vector if not found.
-    Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const REQUIRES(mLock);
+    std::vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const
+            REQUIRES(mLock);
     sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const
             REQUIRES(mLock);
     sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock);
@@ -1023,12 +1022,12 @@
         int32_t deviceId; // id of the device that is currently down, others are rejected
         uint32_t source;  // source of the device that is current down, others are rejected
         int32_t displayId; // id to the display that currently has a touch, others are rejected
-        Vector<TouchedWindow> windows;
+        std::vector<TouchedWindow> windows;
 
         // This collects the portal windows that the touch has gone through. Each portal window
         // targets a display (embedded display for most cases). With this info, we can add the
         // monitoring channels of the displays touched.
-        Vector<sp<InputWindowHandle>> portalWindows;
+        std::vector<sp<InputWindowHandle>> portalWindows;
 
         TouchState();
         ~TouchState();
@@ -1069,7 +1068,7 @@
             nsecs_t currentTime, MotionEntry* entry,
             DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
     void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry,
-            const Vector<InputTarget>& inputTargets) REQUIRES(mLock);
+            const std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
 
     void logOutboundKeyDetails(const char* prefix, const KeyEntry* entry);
     void logOutboundMotionDetails(const char* prefix, const MotionEntry* entry);
@@ -1105,15 +1104,15 @@
 
     int32_t getTargetDisplayId(const EventEntry* entry);
     int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
-            Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) REQUIRES(mLock);
+            std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) REQUIRES(mLock);
     int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
-            Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
+            std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
             bool* outConflictingPointerActions) REQUIRES(mLock);
 
     void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
-            int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets)
+            int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets)
             REQUIRES(mLock);
-    void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets, int32_t displayId,
+    void addMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId,
             float xOffset = 0, float yOffset = 0) REQUIRES(mLock);
 
     void pokeUserActivityLocked(const EventEntry* eventEntry) REQUIRES(mLock);
@@ -1137,8 +1136,9 @@
             EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock);
     void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
             EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock);
-    void enqueueDispatchEntry(const sp<Connection>& connection,
-            EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode);
+    void enqueueDispatchEntryLocked(const sp<Connection>& connection,
+            EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode)
+            REQUIRES(mLock);
     void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
             REQUIRES(mLock);
     void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
@@ -1148,6 +1148,9 @@
     void drainDispatchQueue(Queue<DispatchEntry>* queue);
     void releaseDispatchEntry(DispatchEntry* dispatchEntry);
     static int handleReceiveCallback(int fd, int events, void* data);
+    // The action sent should only be of type AMOTION_EVENT_*
+    void dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action,
+            const sp<IBinder>& newToken) REQUIRES(mLock);
 
     void synthesizeCancelationEventsForAllConnectionsLocked(
             const CancelationOptions& options) REQUIRES(mLock);
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index a403f31..423b69c 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -229,23 +229,23 @@
 
 void QueuedInputListener::notifyConfigurationChanged(
         const NotifyConfigurationChangedArgs* args) {
-    mArgsQueue.push(new NotifyConfigurationChangedArgs(*args));
+    mArgsQueue.push_back(new NotifyConfigurationChangedArgs(*args));
 }
 
 void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
-    mArgsQueue.push(new NotifyKeyArgs(*args));
+    mArgsQueue.push_back(new NotifyKeyArgs(*args));
 }
 
 void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
-    mArgsQueue.push(new NotifyMotionArgs(*args));
+    mArgsQueue.push_back(new NotifyMotionArgs(*args));
 }
 
 void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) {
-    mArgsQueue.push(new NotifySwitchArgs(*args));
+    mArgsQueue.push_back(new NotifySwitchArgs(*args));
 }
 
 void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
-    mArgsQueue.push(new NotifyDeviceResetArgs(*args));
+    mArgsQueue.push_back(new NotifyDeviceResetArgs(*args));
 }
 
 void QueuedInputListener::flush() {
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index b0157a1..3996cca 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -103,14 +103,14 @@
     }
 };
 
-void InputManager::setInputWindows(const Vector<InputWindowInfo>& infos,
+void InputManager::setInputWindows(const std::vector<InputWindowInfo>& infos,
         const sp<ISetInputWindowsListener>& setInputWindowsListener) {
-    std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> handlesPerDisplay;
+    std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> handlesPerDisplay;
 
-    Vector<sp<InputWindowHandle>> handles;
+    std::vector<sp<InputWindowHandle>> handles;
     for (const auto& info : infos) {
-        handlesPerDisplay.emplace(info.displayId, Vector<sp<InputWindowHandle>>());
-        handlesPerDisplay[info.displayId].add(new BinderWindowHandle(info));
+        handlesPerDisplay.emplace(info.displayId, std::vector<sp<InputWindowHandle>>());
+        handlesPerDisplay[info.displayId].push_back(new BinderWindowHandle(info));
     }
     for (auto const& i : handlesPerDisplay) {
         mDispatcher->setInputWindows(i.second, i.first, setInputWindowsListener);
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index ff9a080..e568df5 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -94,7 +94,7 @@
     virtual sp<InputClassifierInterface> getClassifier();
     virtual sp<InputDispatcherInterface> getDispatcher();
 
-    virtual void setInputWindows(const Vector<InputWindowInfo>& handles,
+    virtual void setInputWindows(const std::vector<InputWindowInfo>& handles,
             const sp<ISetInputWindowsListener>& setInputWindowsListener);
     virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
 
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 21ba029..a45b8a5 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -287,7 +287,7 @@
     int32_t oldGeneration;
     int32_t timeoutMillis;
     bool inputDevicesChanged = false;
-    Vector<InputDeviceInfo> inputDevices;
+    std::vector<InputDeviceInfo> inputDevices;
     { // acquire lock
         AutoMutex _l(mLock);
 
@@ -590,12 +590,13 @@
     refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE);
 }
 
-void InputReader::getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices) {
+void InputReader::getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices) {
     for (size_t i = 0; i < mDevices.size(); i++) {
         InputDevice* device = mDevices.valueAt(i);
         if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) {
-            outDevices.push();
-            device->getDeviceInfo(&outDevices.editTop());
+            InputDeviceInfo info;
+            device->getDeviceInfo(&info);
+            outDevices.push_back(info);
         }
     }
 }
@@ -643,20 +644,21 @@
     return ++mGeneration;
 }
 
-void InputReader::getInputDevices(Vector<InputDeviceInfo>& outInputDevices) {
+void InputReader::getInputDevices(std::vector<InputDeviceInfo>& outInputDevices) {
     AutoMutex _l(mLock);
     getInputDevicesLocked(outInputDevices);
 }
 
-void InputReader::getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices) {
+void InputReader::getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices) {
     outInputDevices.clear();
 
     size_t numDevices = mDevices.size();
     for (size_t i = 0; i < numDevices; i++) {
         InputDevice* device = mDevices.valueAt(i);
         if (!device->isIgnored()) {
-            outInputDevices.push();
-            device->getDeviceInfo(&outInputDevices.editTop());
+            InputDeviceInfo info;
+            device->getDeviceInfo(&info);
+            outInputDevices.push_back(info);
         }
     }
 }
@@ -951,7 +953,7 @@
     return mReader->bumpGenerationLocked();
 }
 
-void InputReader::ContextImpl::getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) {
+void InputReader::ContextImpl::getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) {
     // lock is already held by whatever called refreshConfigurationLocked
     mReader->getExternalStylusDevicesLocked(outDevices);
 }
@@ -1031,11 +1033,11 @@
     dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
     dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
 
-    const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
-    if (!ranges.isEmpty()) {
+    const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
+    if (!ranges.empty()) {
         dump += INDENT2 "Motion Ranges:\n";
         for (size_t i = 0; i < ranges.size(); i++) {
-            const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
+            const InputDeviceInfo::MotionRange& range = ranges[i];
             const char* label = getAxisLabel(range.axis);
             char name[32];
             if (label) {
@@ -1059,7 +1061,7 @@
 }
 
 void InputDevice::addMapper(InputMapper* mapper) {
-    mMappers.add(mapper);
+    mMappers.push_back(mapper);
 }
 
 void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) {
@@ -1110,9 +1112,7 @@
             }
         }
 
-        size_t numMappers = mMappers.size();
-        for (size_t i = 0; i < numMappers; i++) {
-            InputMapper* mapper = mMappers[i];
+        for (InputMapper* mapper : mMappers) {
             mapper->configure(when, config, changes);
             mSources |= mapper->getSources();
         }
@@ -1120,9 +1120,7 @@
 }
 
 void InputDevice::reset(nsecs_t when) {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
+    for (InputMapper* mapper : mMappers) {
         mapper->reset(when);
     }
 
@@ -1137,7 +1135,6 @@
     // have side-effects that must be interleaved.  For example, joystick movement events and
     // gamepad button presses are handled by different mappers but they should be dispatched
     // in the order received.
-    size_t numMappers = mMappers.size();
     for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
 #if DEBUG_RAW_EVENTS
         ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
@@ -1161,8 +1158,7 @@
             mDropUntilNextSync = true;
             reset(rawEvent->when);
         } else {
-            for (size_t i = 0; i < numMappers; i++) {
-                InputMapper* mapper = mMappers[i];
+            for (InputMapper* mapper : mMappers) {
                 mapper->process(rawEvent);
             }
         }
@@ -1171,17 +1167,13 @@
 }
 
 void InputDevice::timeoutExpired(nsecs_t when) {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
+    for (InputMapper* mapper : mMappers) {
         mapper->timeoutExpired(when);
     }
 }
 
 void InputDevice::updateExternalStylusState(const StylusState& state) {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
+    for (InputMapper* mapper : mMappers) {
         mapper->updateExternalStylusState(state);
     }
 }
@@ -1189,9 +1181,7 @@
 void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
     outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias,
             mIsExternal, mHasMic);
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
+    for (InputMapper* mapper : mMappers) {
         mapper->populateDeviceInfo(outDeviceInfo);
     }
 }
@@ -1210,9 +1200,7 @@
 
 int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) {
     int32_t result = AKEY_STATE_UNKNOWN;
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
+    for (InputMapper* mapper : mMappers) {
         if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
             // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
             // value.  Otherwise, return AKEY_STATE_UP as long as one mapper reports it.
@@ -1230,9 +1218,7 @@
 bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
         const int32_t* keyCodes, uint8_t* outFlags) {
     bool result = false;
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
+    for (InputMapper* mapper : mMappers) {
         if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
             result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
         }
@@ -1242,50 +1228,39 @@
 
 void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
         int32_t token) {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
+    for (InputMapper* mapper : mMappers) {
         mapper->vibrate(pattern, patternSize, repeat, token);
     }
 }
 
 void InputDevice::cancelVibrate(int32_t token) {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
+    for (InputMapper* mapper : mMappers) {
         mapper->cancelVibrate(token);
     }
 }
 
 void InputDevice::cancelTouch(nsecs_t when) {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
+    for (InputMapper* mapper : mMappers) {
         mapper->cancelTouch(when);
     }
 }
 
 int32_t InputDevice::getMetaState() {
     int32_t result = 0;
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
+    for (InputMapper* mapper : mMappers) {
         result |= mapper->getMetaState();
     }
     return result;
 }
 
 void InputDevice::updateMetaState(int32_t keyCode) {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        mMappers[i]->updateMetaState(keyCode);
+    for (InputMapper* mapper : mMappers) {
+        mapper->updateMetaState(keyCode);
     }
 }
 
 void InputDevice::fadePointer() {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
+    for (InputMapper* mapper : mMappers) {
         mapper->fadePointer();
     }
 }
@@ -1300,9 +1275,7 @@
 }
 
 std::optional<int32_t> InputDevice::getAssociatedDisplay() {
-    size_t numMappers = mMappers.size();
-    for (size_t i = 0; i < numMappers; i++) {
-        InputMapper* mapper = mMappers[i];
+    for (InputMapper* mapper : mMappers) {
         std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplay();
         if (associatedDisplayId) {
             return associatedDisplayId;
@@ -2405,7 +2378,7 @@
         ssize_t keyDownIndex = findKeyDown(scanCode);
         if (keyDownIndex >= 0) {
             // key repeat, be sure to use same keycode as before in case of rotation
-            keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
+            keyCode = mKeyDowns[keyDownIndex].keyCode;
         } else {
             // key down
             if ((policyFlags & POLICY_FLAG_VIRTUAL)
@@ -2417,10 +2390,10 @@
                 mDevice->cancelTouch(when);
             }
 
-            mKeyDowns.push();
-            KeyDown& keyDown = mKeyDowns.editTop();
+            KeyDown keyDown;
             keyDown.keyCode = keyCode;
             keyDown.scanCode = scanCode;
+            mKeyDowns.push_back(keyDown);
         }
 
         mDownTime = when;
@@ -2429,8 +2402,8 @@
         ssize_t keyDownIndex = findKeyDown(scanCode);
         if (keyDownIndex >= 0) {
             // key up, be sure to use same keycode as before in case of rotation
-            keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
-            mKeyDowns.removeAt(size_t(keyDownIndex));
+            keyCode = mKeyDowns[keyDownIndex].keyCode;
+            mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex);
         } else {
             // key was not actually down
             ALOGI("Dropping key up from device %s because the key was not down.  "
@@ -3316,9 +3289,9 @@
 }
 
 void TouchInputMapper::resolveExternalStylusPresence() {
-    Vector<InputDeviceInfo> devices;
+    std::vector<InputDeviceInfo> devices;
     mContext->getExternalStylusDevices(devices);
-    mExternalStylusConnected = !devices.isEmpty();
+    mExternalStylusConnected = !devices.empty();
 
     if (!mExternalStylusConnected) {
         resetExternalStylus();
@@ -3967,7 +3940,7 @@
 }
 
 void TouchInputMapper::configureVirtualKeys() {
-    Vector<VirtualKeyDefinition> virtualKeyDefinitions;
+    std::vector<VirtualKeyDefinition> virtualKeyDefinitions;
     getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions);
 
     mVirtualKeys.clear();
@@ -3976,19 +3949,13 @@
         return;
     }
 
-    mVirtualKeys.setCapacity(virtualKeyDefinitions.size());
-
     int32_t touchScreenLeft = mRawPointerAxes.x.minValue;
     int32_t touchScreenTop = mRawPointerAxes.y.minValue;
     int32_t touchScreenWidth = mRawPointerAxes.getRawWidth();
     int32_t touchScreenHeight = mRawPointerAxes.getRawHeight();
 
-    for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
-        const VirtualKeyDefinition& virtualKeyDefinition =
-                virtualKeyDefinitions[i];
-
-        mVirtualKeys.add();
-        VirtualKey& virtualKey = mVirtualKeys.editTop();
+    for (const VirtualKeyDefinition& virtualKeyDefinition : virtualKeyDefinitions) {
+        VirtualKey virtualKey;
 
         virtualKey.scanCode = virtualKeyDefinition.scanCode;
         int32_t keyCode;
@@ -3998,8 +3965,7 @@
                                   &keyCode, &dummyKeyMetaState, &flags)) {
             ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",
                     virtualKey.scanCode);
-            mVirtualKeys.pop(); // drop the key
-            continue;
+            continue; // drop the key
         }
 
         virtualKey.keyCode = keyCode;
@@ -4017,15 +3983,16 @@
                 * touchScreenHeight / mSurfaceHeight + touchScreenTop;
         virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
                 * touchScreenHeight / mSurfaceHeight + touchScreenTop;
+        mVirtualKeys.push_back(virtualKey);
     }
 }
 
 void TouchInputMapper::dumpVirtualKeys(std::string& dump) {
-    if (!mVirtualKeys.isEmpty()) {
+    if (!mVirtualKeys.empty()) {
         dump += INDENT3 "Virtual Keys:\n";
 
         for (size_t i = 0; i < mVirtualKeys.size(); i++) {
-            const VirtualKey& virtualKey = mVirtualKeys.itemAt(i);
+            const VirtualKey& virtualKey = mVirtualKeys[i];
             dump += StringPrintf(INDENT4 "%zu: scanCode=%d, keyCode=%d, "
                     "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n",
                     i, virtualKey.scanCode, virtualKey.keyCode,
@@ -4347,7 +4314,8 @@
     nsecs_t timeSinceLastReport = now - mStatistics.lastReportTime;
     if (timeSinceLastReport > STATISTICS_REPORT_FREQUENCY) {
         android::util::stats_write(android::util::TOUCH_EVENT_REPORTED,
-                mStatistics.min, mStatistics.max, mStatistics.mean(), mStatistics.stdev());
+                mStatistics.min, mStatistics.max,
+                mStatistics.mean(), mStatistics.stdev(), mStatistics.count);
         mStatistics.reset(now);
     }
 }
@@ -4364,12 +4332,13 @@
 }
 
 void TouchInputMapper::sync(nsecs_t when) {
-    const RawState* last = mRawStatesPending.isEmpty() ?
-            &mCurrentRawState : &mRawStatesPending.top();
+    const RawState* last = mRawStatesPending.empty() ?
+            &mCurrentRawState : &mRawStatesPending.back();
 
     // Push a new state.
-    mRawStatesPending.push();
-    RawState* next = &mRawStatesPending.editTop();
+    mRawStatesPending.emplace_back();
+
+    RawState* next = &mRawStatesPending.back();
     next->clear();
     next->when = when;
 
@@ -4436,7 +4405,7 @@
         cookAndDispatch(mCurrentRawState.when);
     }
     if (count != 0) {
-        mRawStatesPending.removeItemsAt(0, count);
+        mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count);
     }
 
     if (mExternalStylusDataPending) {
@@ -6623,12 +6592,9 @@
             && scaledY >= mPhysicalTop && scaledY <= mPhysicalTop + mPhysicalHeight;
 }
 
-const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(
-        int32_t x, int32_t y) {
-    size_t numVirtualKeys = mVirtualKeys.size();
-    for (size_t i = 0; i < numVirtualKeys; i++) {
-        const VirtualKey& virtualKey = mVirtualKeys[i];
+const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) {
 
+    for (const VirtualKey& virtualKey: mVirtualKeys) {
 #if DEBUG_VIRTUAL_KEYS
         ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
                 "left=%d, top=%d, right=%d, bottom=%d",
@@ -6838,9 +6804,7 @@
         return AKEY_STATE_VIRTUAL;
     }
 
-    size_t numVirtualKeys = mVirtualKeys.size();
-    for (size_t i = 0; i < numVirtualKeys; i++) {
-        const VirtualKey& virtualKey = mVirtualKeys[i];
+    for (const VirtualKey& virtualKey : mVirtualKeys) {
         if (virtualKey.keyCode == keyCode) {
             return AKEY_STATE_UP;
         }
@@ -6854,9 +6818,7 @@
         return AKEY_STATE_VIRTUAL;
     }
 
-    size_t numVirtualKeys = mVirtualKeys.size();
-    for (size_t i = 0; i < numVirtualKeys; i++) {
-        const VirtualKey& virtualKey = mVirtualKeys[i];
+    for (const VirtualKey& virtualKey : mVirtualKeys) {
         if (virtualKey.scanCode == scanCode) {
             return AKEY_STATE_UP;
         }
@@ -6867,10 +6829,7 @@
 
 bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
         const int32_t* keyCodes, uint8_t* outFlags) {
-    size_t numVirtualKeys = mVirtualKeys.size();
-    for (size_t i = 0; i < numVirtualKeys; i++) {
-        const VirtualKey& virtualKey = mVirtualKeys[i];
-
+    for (const VirtualKey& virtualKey : mVirtualKeys) {
         for (size_t i = 0; i < numCodes; i++) {
             if (virtualKey.keyCode == keyCodes[i]) {
                 outFlags[i] = 1;
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index fed55ac..9777779 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -90,7 +90,7 @@
     virtual void requestTimeoutAtTime(nsecs_t when) = 0;
     virtual int32_t bumpGeneration() = 0;
 
-    virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) = 0;
+    virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) = 0;
     virtual void dispatchExternalStylusState(const StylusState& outState) = 0;
 
     virtual InputReaderPolicyInterface* getPolicy() = 0;
@@ -124,7 +124,7 @@
 
     virtual void loopOnce();
 
-    virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices);
+    virtual void getInputDevices(std::vector<InputDeviceInfo>& outInputDevices);
 
     virtual bool isInputDeviceEnabled(int32_t deviceId);
 
@@ -166,7 +166,7 @@
         virtual void fadePointer();
         virtual void requestTimeoutAtTime(nsecs_t when);
         virtual int32_t bumpGeneration();
-        virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices);
+        virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices);
         virtual void dispatchExternalStylusState(const StylusState& outState);
         virtual InputReaderPolicyInterface* getPolicy();
         virtual InputListenerInterface* getListener();
@@ -211,7 +211,7 @@
     int32_t getGlobalMetaStateLocked();
 
     void notifyExternalStylusPresenceChanged();
-    void getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices);
+    void getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices);
     void dispatchExternalStylusState(const StylusState& state);
 
     void fadePointerLocked();
@@ -219,7 +219,7 @@
     int32_t mGeneration;
     int32_t bumpGenerationLocked();
 
-    void getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices);
+    void getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices);
 
     nsecs_t mDisableVirtualKeysTimeout;
     void disableVirtualKeysUntilLocked(nsecs_t time);
@@ -266,7 +266,7 @@
     inline void setMic(bool hasMic) { mHasMic = hasMic; }
     inline bool hasMic() const { return mHasMic; }
 
-    inline bool isIgnored() { return mMappers.isEmpty(); }
+    inline bool isIgnored() { return mMappers.empty(); }
 
     bool isEnabled();
     void setEnabled(bool enabled, nsecs_t when);
@@ -331,7 +331,7 @@
     std::string mAlias;
     uint32_t mClasses;
 
-    Vector<InputMapper*> mMappers;
+    std::vector<InputMapper*> mMappers;
 
     uint32_t mSources;
     bool mIsExternal;
@@ -877,7 +877,7 @@
     uint32_t mSource;
     int32_t mKeyboardType;
 
-    Vector<KeyDown> mKeyDowns; // keys that are down
+    std::vector<KeyDown> mKeyDowns; // keys that are down
     int32_t mMetaState;
     nsecs_t mDownTime; // time of most recent key down
 
@@ -1235,7 +1235,7 @@
         }
     };
 
-    Vector<RawState> mRawStatesPending;
+    std::vector<RawState> mRawStatesPending;
     RawState mCurrentRawState;
     CookedState mCurrentCookedState;
     RawState mLastRawState;
@@ -1262,7 +1262,7 @@
     // The pointer controller, or null if the device is not a pointer.
     sp<PointerControllerInterface> mPointerController;
 
-    Vector<VirtualKey> mVirtualKeys;
+    std::vector<VirtualKey> mVirtualKeys;
 
     virtual void configureParameters();
     virtual void dumpParameters(std::string& dump);
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index a00b5fb..d8b352c 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -40,7 +40,8 @@
     InputFlinger() ANDROID_API;
 
     virtual status_t dump(int fd, const Vector<String16>& args);
-    void setInputWindows(const Vector<InputWindowInfo>&, const sp<ISetInputWindowsListener>&) {}
+    void setInputWindows(const std::vector<InputWindowInfo>&,
+            const sp<ISetInputWindowsListener>&) {}
     void transferTouchFocus(const sp<IBinder>&, const sp<IBinder>&) {}
     void registerInputChannel(const sp<InputChannel>&) {}
     void unregisterInputChannel(const sp<InputChannel>&) {}
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index cd8caf7..b51dcb6 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -221,7 +221,7 @@
 
 private:
     sp<InputListenerInterface> mInnerListener;
-    Vector<NotifyArgs*> mArgsQueue;
+    std::vector<NotifyArgs*> mArgsQueue;
 };
 
 } // namespace android
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index fe1d4d0..8ad5dd0 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -74,7 +74,7 @@
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices) = 0;
+    virtual void getInputDevices(std::vector<InputDeviceInfo>& outInputDevices) = 0;
 
     /* Query current input state. */
     virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
@@ -333,7 +333,7 @@
     /* Notifies the input reader policy that some input devices have changed
      * and provides information about all current input devices.
      */
-    virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) = 0;
+    virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) = 0;
 
     /* Gets the keyboard layout for a particular input device. */
     virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 3b6fe52..745fac0 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -340,10 +340,7 @@
     virtual ~FakeApplicationHandle() {}
 
     virtual bool updateInfo() {
-        if (!mInfo) {
-            mInfo = new InputApplicationInfo();
-        }
-        mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
+        mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
         return true;
     }
 };
@@ -571,8 +568,8 @@
     sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window",
             ADISPLAY_ID_DEFAULT);
 
-    Vector<sp<InputWindowHandle>> inputWindowHandles;
-    inputWindowHandles.add(window);
+    std::vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.push_back(window);
 
     mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
     ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
@@ -591,9 +588,9 @@
     sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
             ADISPLAY_ID_DEFAULT);
 
-    Vector<sp<InputWindowHandle>> inputWindowHandles;
-    inputWindowHandles.add(windowTop);
-    inputWindowHandles.add(windowSecond);
+    std::vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.push_back(windowTop);
+    inputWindowHandles.push_back(windowSecond);
 
     mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
     ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
@@ -617,9 +614,9 @@
 
     // Expect one focus window exist in display.
     windowSecond->setFocus();
-    Vector<sp<InputWindowHandle>> inputWindowHandles;
-    inputWindowHandles.add(windowTop);
-    inputWindowHandles.add(windowSecond);
+    std::vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.push_back(windowTop);
+    inputWindowHandles.push_back(windowSecond);
 
     mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
     ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
@@ -643,9 +640,9 @@
     // 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);
+    std::vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.push_back(windowTop);
+    inputWindowHandles.push_back(windowSecond);
 
     mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
     ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
@@ -669,9 +666,9 @@
 
     windowTop->setFocus();
     windowSecond->setFocus();
-    Vector<sp<InputWindowHandle>> inputWindowHandles;
-    inputWindowHandles.add(windowTop);
-    inputWindowHandles.add(windowSecond);
+    std::vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.push_back(windowTop);
+    inputWindowHandles.push_back(windowSecond);
     // Release channel for window is no longer valid.
     windowTop->releaseChannel();
     mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
@@ -695,8 +692,8 @@
         application1 = new FakeApplicationHandle();
         windowInPrimary = new FakeWindowHandle(application1, mDispatcher, "D_1",
                 ADISPLAY_ID_DEFAULT);
-        Vector<sp<InputWindowHandle>> inputWindowHandles;
-        inputWindowHandles.push(windowInPrimary);
+        std::vector<sp<InputWindowHandle>> inputWindowHandles;
+        inputWindowHandles.push_back(windowInPrimary);
         // Set focus window for primary display, but focused display would be second one.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
         windowInPrimary->setFocus();
@@ -706,8 +703,8 @@
         windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2",
                 SECOND_DISPLAY_ID);
         // Set focus to second display window.
-        Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
-        inputWindowHandles_Second.push(windowInSecondary);
+        std::vector<sp<InputWindowHandle>> inputWindowHandles_Second;
+        inputWindowHandles_Second.push_back(windowInSecondary);
         // Set focus display to second one.
         mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
         // Set focus window for second display.
@@ -762,7 +759,7 @@
     windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
 
     // Remove secondary display.
-    Vector<sp<InputWindowHandle>> noWindows;
+    std::vector<sp<InputWindowHandle>> noWindows;
     mDispatcher->setInputWindows(noWindows, SECOND_DISPLAY_ID);
 
     // Expect old focus should receive a cancel event.
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 80a55f1..d353028 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -158,7 +158,7 @@
 class FakeInputReaderPolicy : public InputReaderPolicyInterface {
     InputReaderConfiguration mConfig;
     KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers;
-    Vector<InputDeviceInfo> mInputDevices;
+    std::vector<InputDeviceInfo> mInputDevices;
     std::vector<DisplayViewport> mViewports;
     TouchAffineTransformation transform;
 
@@ -226,7 +226,7 @@
         return &mConfig;
     }
 
-    const Vector<InputDeviceInfo>& getInputDevices() const {
+    const std::vector<InputDeviceInfo>& getInputDevices() const {
         return mInputDevices;
     }
 
@@ -280,7 +280,7 @@
         return mPointerControllers.valueFor(deviceId);
     }
 
-    virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) {
+    virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) {
         mInputDevices = inputDevices;
     }
 
@@ -314,7 +314,7 @@
         KeyedVector<int32_t, KeyInfo> keysByScanCode;
         KeyedVector<int32_t, KeyInfo> keysByUsageCode;
         KeyedVector<int32_t, bool> leds;
-        Vector<VirtualKeyDefinition> virtualKeys;
+        std::vector<VirtualKeyDefinition> virtualKeys;
         bool enabled;
 
         status_t enable() {
@@ -482,7 +482,7 @@
 
     void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) {
         Device* device = getDevice(deviceId);
-        device->virtualKeys.push(definition);
+        device->virtualKeys.push_back(definition);
     }
 
     void enqueueEvent(nsecs_t when, int32_t deviceId, int32_t type,
@@ -728,12 +728,12 @@
     }
 
     virtual void getVirtualKeyDefinitions(int32_t deviceId,
-            Vector<VirtualKeyDefinition>& outVirtualKeys) const {
+            std::vector<VirtualKeyDefinition>& outVirtualKeys) const {
         outVirtualKeys.clear();
 
         Device* device = getDevice(deviceId);
         if (device) {
-            outVirtualKeys.appendVector(device->virtualKeys);
+            outVirtualKeys = device->virtualKeys;
         }
     }
 
@@ -842,7 +842,7 @@
         return ++mGeneration;
     }
 
-    virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) {
+    virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) {
 
     }
 
@@ -865,7 +865,7 @@
     KeyedVector<int32_t, int32_t> mKeyCodeStates;
     KeyedVector<int32_t, int32_t> mScanCodeStates;
     KeyedVector<int32_t, int32_t> mSwitchStates;
-    Vector<int32_t> mSupportedKeyCodes;
+    std::vector<int32_t> mSupportedKeyCodes;
     RawEvent mLastEvent;
 
     bool mConfigureWasCalled;
@@ -925,7 +925,7 @@
     }
 
     void addSupportedKeyCode(int32_t keyCode) {
-        mSupportedKeyCodes.add(keyCode);
+        mSupportedKeyCodes.push_back(keyCode);
     }
 
 private:
@@ -1309,7 +1309,7 @@
             0, nullptr)); // no classes so device will be ignored
 
 
-    Vector<InputDeviceInfo> inputDevices;
+    std::vector<InputDeviceInfo> inputDevices;
     mReader->getInputDevices(inputDevices);
 
     ASSERT_EQ(1U, inputDevices.size());
@@ -4436,7 +4436,7 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
     ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
 
-    // airbrush
+    // air-brush
     processKey(mapper, BTN_TOOL_PENCIL, 0);
     processKey(mapper, BTN_TOOL_AIRBRUSH, 1);
     processSync(mapper);
@@ -5943,7 +5943,7 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
     ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
 
-    // airbrush
+    // air-brush
     processKey(mapper, BTN_TOOL_PENCIL, 0);
     processKey(mapper, BTN_TOOL_AIRBRUSH, 1);
     processSync(mapper);
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 189ae36..a6ed75f 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -359,7 +359,7 @@
     for (const auto & s : mSensorList) {
         int32_t handle = s.handle;
         const Info& info = mActivationCount.valueFor(handle);
-        if (info.batchParams.isEmpty()) continue;
+        if (info.numActiveClients() == 0) continue;
 
         result.appendFormat("0x%08x) active-count = %zu; ", handle, info.batchParams.size());
 
@@ -730,6 +730,15 @@
     return mDisabledClients.indexOf(ident) >= 0;
 }
 
+bool SensorDevice::isSensorActive(int handle) const {
+    Mutex::Autolock _l(mLock);
+    ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+    if (activationIndex < 0) {
+        return false;
+    }
+    return mActivationCount.valueAt(activationIndex).numActiveClients() > 0;
+}
+
 void SensorDevice::enableAllSensors() {
     if (mSensors == nullptr) return;
     Mutex::Autolock _l(mLock);
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 2a69654..71b918f 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -120,6 +120,8 @@
         return mReconnecting;
     }
 
+    bool isSensorActive(int handle) const;
+
     // Dumpable
     virtual std::string dump() const;
 private:
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index b66cbcf..c4cfdc6 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -78,7 +78,14 @@
 
 void SensorService::SensorEventConnection::dump(String8& result) {
     Mutex::Autolock _l(mConnectionLock);
-    result.appendFormat("\tOperating Mode: %s\n",mDataInjectionMode ? "DATA_INJECTION" : "NORMAL");
+    result.appendFormat("\tOperating Mode: ");
+    if (!mService->isWhiteListedPackage(getPackageName())) {
+        result.append("RESTRICTED\n");
+    } else if (mDataInjectionMode) {
+        result.append("DATA_INJECTION\n");
+    } else {
+        result.append("NORMAL\n");
+    }
     result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | "
             "max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize,
             mMaxCacheSize);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3fbd61e..e3dfde4 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -441,12 +441,15 @@
             }
 
             result.append("Active sensors:\n");
+            SensorDevice& dev = SensorDevice::getInstance();
             for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
                 int handle = mActiveSensors.keyAt(i);
-                result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
-                        getSensorName(handle).string(),
-                        handle,
-                        mActiveSensors.valueAt(i)->getNumConnections());
+                if (dev.isSensorActive(handle)) {
+                    result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
+                            getSensorName(handle).string(),
+                            handle,
+                            mActiveSensors.valueAt(i)->getNumConnections());
+                }
             }
 
             result.appendFormat("Socket Buffer size = %zd events\n",
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index ac1d492..c3324af 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -138,8 +138,9 @@
         "LayerVector.cpp",
         "MonitoredProducer.cpp",
         "NativeWindowSurface.cpp",
-        "RenderArea.cpp",
+        "RefreshRateOverlay.cpp",
         "RegionSamplingThread.cpp",
+        "RenderArea.cpp",
         "Scheduler/DispSync.cpp",
         "Scheduler/DispSyncSource.cpp",
         "Scheduler/EventControlThread.cpp",
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index cc78ece..f2d4c51 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -323,7 +323,8 @@
                                        mCurrentTextureBuffer == nullptr
                                                ? nullptr
                                                : mCurrentTextureBuffer->graphicBuffer(),
-                                       mCurrentCrop, mCurrentTransform, mFilteringEnabled);
+                                       getCurrentCropLocked(), mCurrentTransform,
+                                       mFilteringEnabled);
 }
 
 nsecs_t BufferLayerConsumer::getTimestamp() {
@@ -380,6 +381,10 @@
 
 Rect BufferLayerConsumer::getCurrentCrop() const {
     Mutex::Autolock lock(mMutex);
+    return getCurrentCropLocked();
+}
+
+Rect BufferLayerConsumer::getCurrentCropLocked() const {
     return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
             ? GLConsumer::scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
             : mCurrentCrop;
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 32ccfbb..f4ca846 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -253,6 +253,9 @@
     // access the current texture buffer.
     status_t doFenceWaitLocked() const;
 
+    // getCurrentCropLocked returns the cropping rectangle of the current buffer.
+    Rect getCurrentCropLocked() const;
+
     // The default consumer usage flags that BufferLayerConsumer always sets on its
     // BufferQueue instance; these will be OR:d with any additional flags passed
     // from the BufferLayerConsumer user. In particular, BufferLayerConsumer will always
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e4179ee..d3b36fe 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -361,8 +361,12 @@
 
     uint32_t hwcSlot = 0;
     sp<GraphicBuffer> hwcBuffer;
+
+    // INVALID_BUFFER_SLOT is used to identify BufferStateLayers.  Default to 0
+    // for BufferQueueLayers
+    int slot = (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot;
     (*outputLayer->editState().hwc)
-            .hwcBufferCache.getHwcBuffer(mActiveBuffer, &hwcSlot, &hwcBuffer);
+            .hwcBufferCache.getHwcBuffer(slot, mActiveBuffer, &hwcSlot, &hwcBuffer);
 
     auto acquireFence = mConsumer->getCurrentFence();
     auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 1ca0b02..64dfdc3 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -139,7 +139,6 @@
 
 bool BufferStateLayer::setTransform(uint32_t transform) {
     if (mCurrentState.transform == transform) return false;
-    mCurrentState.sequence++;
     mCurrentState.transform = transform;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -170,7 +169,6 @@
     }
 
     if (mCurrentState.crop == c) return false;
-    mCurrentState.sequence++;
     mCurrentState.crop = c;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -242,7 +240,6 @@
 
 bool BufferStateLayer::setHdrMetadata(const HdrMetadata& hdrMetadata) {
     if (mCurrentState.hdrMetadata == hdrMetadata) return false;
-    mCurrentState.sequence++;
     mCurrentState.hdrMetadata = hdrMetadata;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -250,7 +247,6 @@
 }
 
 bool BufferStateLayer::setSurfaceDamageRegion(const Region& surfaceDamage) {
-    mCurrentState.sequence++;
     mCurrentState.surfaceDamageRegion = surfaceDamage;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -259,7 +255,6 @@
 
 bool BufferStateLayer::setApi(int32_t api) {
     if (mCurrentState.api == api) return false;
-    mCurrentState.sequence++;
     mCurrentState.api = api;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -268,7 +263,6 @@
 
 bool BufferStateLayer::setSidebandStream(const sp<NativeHandle>& sidebandStream) {
     if (mCurrentState.sidebandStream == sidebandStream) return false;
-    mCurrentState.sequence++;
     mCurrentState.sidebandStream = sidebandStream;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -551,6 +545,8 @@
     mFlinger->mTimeStats->setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
     mFlinger->mTimeStats->setLatchTime(layerID, getFrameNumber(), latchTime);
 
+    mCurrentStateModified = false;
+
     return NO_ERROR;
 }
 
@@ -589,10 +585,10 @@
 
     const State& s(getDrawingState());
 
-    // obtain slot
-    uint32_t hwcSlot = 0;
+    uint32_t hwcSlot;
     sp<GraphicBuffer> buffer;
-    hwcInfo.hwcBufferCache.getHwcBuffer(s.buffer, &hwcSlot, &buffer);
+    hwcInfo.hwcBufferCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, s.buffer, &hwcSlot,
+                                        &buffer);
 
     auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence);
     if (error != HWC2::Error::None) {
@@ -600,7 +596,6 @@
               s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
-    mCurrentStateModified = false;
     mFrameNumber++;
 }
 
diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp
index cb02d16..51ca45c 100644
--- a/services/surfaceflinger/BufferStateLayerCache.cpp
+++ b/services/surfaceflinger/BufferStateLayerCache.cpp
@@ -23,21 +23,14 @@
 
 #include "BufferStateLayerCache.h"
 
-#define VALID_CACHE_ID(id) ((id) >= 0 || (id) < (BUFFER_CACHE_MAX_SIZE))
-
 namespace android {
 
 ANDROID_SINGLETON_STATIC_INSTANCE(BufferStateLayerCache);
 
 BufferStateLayerCache::BufferStateLayerCache() : mDeathRecipient(new CacheDeathRecipient) {}
 
-void BufferStateLayerCache::add(sp<IBinder> processToken, int32_t id,
+void BufferStateLayerCache::add(const sp<IBinder>& processToken, uint64_t id,
                                 const sp<GraphicBuffer>& buffer) {
-    if (!VALID_CACHE_ID(id)) {
-        ALOGE("failed to cache buffer: invalid buffer id");
-        return;
-    }
-
     if (!processToken) {
         ALOGE("failed to cache buffer: invalid process token");
         return;
@@ -61,15 +54,33 @@
     }
 
     auto& processBuffers = mBuffers[processToken];
+
+    if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
+        ALOGE("failed to cache buffer: cache is full");
+        return;
+    }
+
     processBuffers[id] = buffer;
 }
 
-sp<GraphicBuffer> BufferStateLayerCache::get(sp<IBinder> processToken, int32_t id) {
-    if (!VALID_CACHE_ID(id)) {
-        ALOGE("failed to get buffer: invalid buffer id");
-        return nullptr;
+void BufferStateLayerCache::erase(const sp<IBinder>& processToken, uint64_t id) {
+    if (!processToken) {
+        ALOGE("failed to uncache buffer: invalid process token");
+        return;
     }
 
+    std::lock_guard lock(mMutex);
+
+    if (mBuffers.find(processToken) == mBuffers.end()) {
+        ALOGE("failed to uncache buffer: process token not found");
+        return;
+    }
+
+    auto& processBuffers = mBuffers[processToken];
+    processBuffers.erase(id);
+}
+
+sp<GraphicBuffer> BufferStateLayerCache::get(const sp<IBinder>& processToken, uint64_t id) {
     if (!processToken) {
         ALOGE("failed to cache buffer: invalid process token");
         return nullptr;
@@ -82,8 +93,8 @@
         return nullptr;
     }
 
-    if (id >= itr->second.size()) {
-        ALOGE("failed to get buffer: id outside the bounds of the cache");
+    if (itr->second.find(id) == itr->second.end()) {
+        ALOGE("failed to get buffer: buffer not found");
         return nullptr;
     }
 
diff --git a/services/surfaceflinger/BufferStateLayerCache.h b/services/surfaceflinger/BufferStateLayerCache.h
index ede3feb..415c09c 100644
--- a/services/surfaceflinger/BufferStateLayerCache.h
+++ b/services/surfaceflinger/BufferStateLayerCache.h
@@ -34,14 +34,16 @@
 public:
     BufferStateLayerCache();
 
-    void add(sp<IBinder> processToken, int32_t id, const sp<GraphicBuffer>& buffer);
-    sp<GraphicBuffer> get(sp<IBinder> processToken, int32_t id);
+    void add(const sp<IBinder>& processToken, uint64_t id, const sp<GraphicBuffer>& buffer);
+    void erase(const sp<IBinder>& processToken, uint64_t id);
+
+    sp<GraphicBuffer> get(const sp<IBinder>& processToken, uint64_t id);
 
     void removeProcess(const wp<IBinder>& processToken);
 
 private:
     std::mutex mMutex;
-    std::map<wp<IBinder> /*caching process*/, std::array<sp<GraphicBuffer>, BUFFER_CACHE_MAX_SIZE>>
+    std::map<wp<IBinder> /*caching process*/, std::map<uint64_t /*Cache id*/, sp<GraphicBuffer>>>
             mBuffers GUARDED_BY(mMutex);
 
     class CacheDeathRecipient : public IBinder::DeathRecipient {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index 02d7890..97bdc8f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -45,7 +45,7 @@
     //
     // outBuffer is set to buffer when buffer is not in the HWC cache;
     // otherwise, outBuffer is set to nullptr.
-    void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+    void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                       sp<GraphicBuffer>* outBuffer);
 
 protected:
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index 8613210..a941e09 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -48,12 +48,20 @@
     return std::distance(std::begin(mBuffers), iter);
 }
 
-void HwcBufferCache::getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                                   sp<GraphicBuffer>* outBuffer) {
-    bool cached = getSlot(buffer, outSlot);
+    // if this slot corresponds to a BufferStateLayer, generate the slot
+    if (slot == BufferQueue::INVALID_BUFFER_SLOT) {
+        getSlot(buffer, outSlot);
+    } else if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) {
+        *outSlot = 0;
+    } else {
+        *outSlot = slot;
+    }
 
     auto& [currentCounter, currentBuffer] = mBuffers[*outSlot];
-    if (cached) {
+    wp<GraphicBuffer> weakCopy(buffer);
+    if (currentBuffer == weakCopy) {
         // already cached in HWC, skip sending the buffer
         *outBuffer = nullptr;
         currentCounter = getCounter();
diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
index ac04cb3..b261493 100644
--- a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
@@ -24,9 +24,9 @@
 
 class TestableHwcBufferCache : public impl::HwcBufferCache {
 public:
-    void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+    void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                       sp<GraphicBuffer>* outBuffer) {
-        HwcBufferCache::getHwcBuffer(buffer, outSlot, outBuffer);
+        HwcBufferCache::getHwcBuffer(slot, buffer, outSlot, outBuffer);
     }
     bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) {
         return HwcBufferCache::getSlot(buffer, outSlot);
@@ -38,64 +38,88 @@
 public:
     ~HwcBufferCacheTest() override = default;
 
-    TestableHwcBufferCache mCache;
+    void testSlot(const int inSlot, const uint32_t expectedSlot) {
+        uint32_t outSlot;
+        sp<GraphicBuffer> outBuffer;
+
+        // The first time, the output  is the same as the input
+        mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
+        EXPECT_EQ(expectedSlot, outSlot);
+        EXPECT_EQ(mBuffer1, outBuffer);
+
+        // The second time with the same buffer, the outBuffer is nullptr.
+        mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
+        EXPECT_EQ(expectedSlot, outSlot);
+        EXPECT_EQ(nullptr, outBuffer.get());
+
+        // With a new buffer, the outBuffer is the input.
+        mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
+        EXPECT_EQ(expectedSlot, outSlot);
+        EXPECT_EQ(mBuffer2, outBuffer);
+
+        // Again, the second request with the same buffer sets outBuffer to nullptr.
+        mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
+        EXPECT_EQ(expectedSlot, outSlot);
+        EXPECT_EQ(nullptr, outBuffer.get());
+
+        // Setting a slot to use nullptr lookslike works, but note that
+        // the output values make it look like no new buffer is being set....
+        mCache.getHwcBuffer(inSlot, sp<GraphicBuffer>(), &outSlot, &outBuffer);
+        EXPECT_EQ(expectedSlot, outSlot);
+        EXPECT_EQ(nullptr, outBuffer.get());
+    }
+
+    impl::HwcBufferCache mCache;
     sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
     sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
 };
 
-TEST_F(HwcBufferCacheTest, testSlot) {
+TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) {
+    testSlot(0, 0);
+}
+
+TEST_F(HwcBufferCacheTest, cacheWorksForMaxSlot) {
+    testSlot(BufferQueue::NUM_BUFFER_SLOTS - 1, BufferQueue::NUM_BUFFER_SLOTS - 1);
+}
+
+TEST_F(HwcBufferCacheTest, cacheMapsNegativeSlotToZero) {
+    testSlot(-123, 0);
+}
+
+TEST_F(HwcBufferCacheTest, cacheGeneratesSlotForInvalidBufferSlot) {
     uint32_t outSlot;
     sp<GraphicBuffer> outBuffer;
 
-    // The first time, the output  is the same as the input
-    mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
+    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer);
     EXPECT_EQ(0, outSlot);
     EXPECT_EQ(mBuffer1, outBuffer);
 
-    // The second time with the same buffer, the outBuffer is nullptr.
-    mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
+    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer);
     EXPECT_EQ(0, outSlot);
     EXPECT_EQ(nullptr, outBuffer.get());
 
-    // With a new buffer, the outBuffer is the input.
-    mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer);
+    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer);
     EXPECT_EQ(1, outSlot);
     EXPECT_EQ(mBuffer2, outBuffer);
 
-    // Again, the second request with the same buffer sets outBuffer to nullptr.
-    mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer);
+    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer);
     EXPECT_EQ(1, outSlot);
     EXPECT_EQ(nullptr, outBuffer.get());
 
-    // Setting a slot to use nullptr lookslike works, but note that
-    // the output values make it look like no new buffer is being set....
-    mCache.getHwcBuffer(sp<GraphicBuffer>(), &outSlot, &outBuffer);
+    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, sp<GraphicBuffer>(), &outSlot,
+                        &outBuffer);
     EXPECT_EQ(2, outSlot);
     EXPECT_EQ(nullptr, outBuffer.get());
-}
 
-TEST_F(HwcBufferCacheTest, testGetLeastRecentlyUsedSlot) {
-    int slot;
-    uint32_t outSlot;
-    sp<GraphicBuffer> outBuffer;
-
-    // fill up cache
-    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
-        sp<GraphicBuffer> buf{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
-        mCache.getHwcBuffer(buf, &outSlot, &outBuffer);
-        EXPECT_EQ(buf, outBuffer);
-        EXPECT_EQ(i, outSlot);
-    }
-
-    slot = mCache.getLeastRecentlyUsedSlot();
-    EXPECT_EQ(0, slot);
-
-    mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
-    EXPECT_EQ(0, outSlot);
+    // note that sending mBuffer1 with explicit slot 1 will overwrite mBuffer2
+    // and also cause mBuffer1 to be stored in two places
+    mCache.getHwcBuffer(1, mBuffer1, &outSlot, &outBuffer);
+    EXPECT_EQ(1, outSlot);
     EXPECT_EQ(mBuffer1, outBuffer);
 
-    slot = mCache.getLeastRecentlyUsedSlot();
-    EXPECT_EQ(1, slot);
+    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer);
+    EXPECT_EQ(3, outSlot);
+    EXPECT_EQ(mBuffer2, outBuffer);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 7927fa9..ad08a92 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -42,4 +42,32 @@
 void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
                                      const Rect&, int32_t, const ui::Dataspace) {}
 
+Layer::RoundedCornerState ContainerLayer::getRoundedCornerStateInternal(
+        const FloatRect bounds) const {
+    const auto& p = mDrawingParent.promote();
+    if (p != nullptr) {
+        RoundedCornerState parentState = p->getRoundedCornerStateInternal(bounds);
+        if (parentState.radius > 0) {
+            ui::Transform t = getActiveTransform(getDrawingState());
+            t = t.inverse();
+            parentState.cropRect = t.transform(parentState.cropRect);
+            // The rounded corners shader only accepts 1 corner radius for performance reasons,
+            // but a transform matrix can define horizontal and vertical scales.
+            // Let's take the average between both of them and pass into the shader, practically we
+            // never do this type of transformation on windows anyway.
+            parentState.radius *= (t[0][0] + t[1][1]) / 2.0f;
+            return parentState;
+        }
+    }
+    const float radius = getDrawingState().cornerRadius;
+    if (radius > 0) {
+        const Rect crop = getCrop(getDrawingState());
+        if (!crop.isEmpty()) {
+            return RoundedCornerState(bounds.intersect(crop.toFloatRect()), radius);
+        }
+        return RoundedCornerState(bounds, radius);
+    }
+    return RoundedCornerState();
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 7222a3e..cd8e722 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -40,6 +40,7 @@
     bool isCreatedFromMainThread() const override { return true; }
 
     bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
+    Layer::RoundedCornerState getRoundedCornerStateInternal(const FloatRect bounds) const override;
 
 protected:
     bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 775fb80..7370b0c 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -111,7 +111,7 @@
     BufferItem item;
     status_t err = acquireBufferLocked(&item, 0);
     if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-        mHwcBufferCache.getHwcBuffer(mCurrentBuffer, &outSlot, &outBuffer);
+        mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, &outSlot, &outBuffer);
         return NO_ERROR;
     } else if (err != NO_ERROR) {
         ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
@@ -137,7 +137,7 @@
     mCurrentFence = item.mFence;
 
     outFence = item.mFence;
-    mHwcBufferCache.getHwcBuffer(mCurrentBuffer, &outSlot, &outBuffer);
+    mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, &outSlot, &outBuffer);
     outDataspace = static_cast<Dataspace>(item.mDataSpace);
     status_t result = mHwc.setClientTarget(mDisplayId, outSlot, outFence, outBuffer, outDataspace);
     if (result != NO_ERROR) {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 613dc77..4e0e4df 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -224,7 +224,7 @@
     if (fbBuffer != nullptr) {
         uint32_t hwcSlot = 0;
         sp<GraphicBuffer> hwcBuffer;
-        mHwcBufferCache.getHwcBuffer(fbBuffer, &hwcSlot, &hwcBuffer);
+        mHwcBufferCache.getHwcBuffer(mFbProducerSlot, fbBuffer, &hwcSlot, &hwcBuffer);
 
         // TODO: Correctly propagate the dataspace from GL composition
         result = mHwc.setClientTarget(*mDisplayId, hwcSlot, mFbFence, hwcBuffer,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 512a0b4..73f27e4 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1788,9 +1788,13 @@
 }
 
 Layer::RoundedCornerState Layer::getRoundedCornerState() const {
+    return getRoundedCornerStateInternal(mSourceBounds);
+}
+
+Layer::RoundedCornerState Layer::getRoundedCornerStateInternal(const FloatRect) const {
     const auto& p = mDrawingParent.promote();
     if (p != nullptr) {
-        RoundedCornerState parentState = p->getRoundedCornerState();
+        RoundedCornerState parentState = p->getRoundedCornerStateInternal(mSourceBounds);
         if (parentState.radius > 0) {
             ui::Transform t = getActiveTransform(getDrawingState());
             t = t.inverse();
@@ -1804,7 +1808,10 @@
         }
     }
     const float radius = getDrawingState().cornerRadius;
-    return radius > 0 ? RoundedCornerState(getBounds(), radius) : RoundedCornerState();
+    return radius > 0
+            ? RoundedCornerState(mSourceBounds.intersect(getCrop(getDrawingState()).toFloatRect()),
+                                 radius)
+            : RoundedCornerState();
 }
 
 void Layer::commitChildList() {
@@ -1839,7 +1846,8 @@
     setTransactionFlags(eTransactionNeeded);
 }
 
-void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet) {
+void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet,
+                         uint32_t traceFlags) {
     const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
     const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
     const State& state = useDrawing ? mDrawingState : mCurrentState;
@@ -1847,114 +1855,129 @@
     ui::Transform requestedTransform = state.active_legacy.transform;
     ui::Transform transform = getTransform();
 
-    layerInfo->set_id(sequence);
-    layerInfo->set_name(getName().c_str());
-    layerInfo->set_type(String8(getTypeId()));
+    if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
+        layerInfo->set_id(sequence);
+        layerInfo->set_name(getName().c_str());
+        layerInfo->set_type(String8(getTypeId()));
 
-    for (const auto& child : children) {
-        layerInfo->add_children(child->sequence);
-    }
-
-    for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
-        sp<Layer> strongRelative = weakRelative.promote();
-        if (strongRelative != nullptr) {
-            layerInfo->add_relatives(strongRelative->sequence);
+        for (const auto& child : children) {
+            layerInfo->add_children(child->sequence);
         }
-    }
 
-    LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
-                                   [&]() { return layerInfo->mutable_transparent_region(); });
-    LayerProtoHelper::writeToProto(visibleRegion,
-                                   [&]() { return layerInfo->mutable_visible_region(); });
-    LayerProtoHelper::writeToProto(surfaceDamageRegion,
-                                   [&]() { return layerInfo->mutable_damage_region(); });
-
-    layerInfo->set_layer_stack(getLayerStack());
-    layerInfo->set_z(state.z);
-
-    LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
-                                           [&]() { return layerInfo->mutable_position(); });
-
-    LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() {
-        return layerInfo->mutable_requested_position();
-    });
-
-    LayerProtoHelper::writeSizeToProto(state.active_legacy.w, state.active_legacy.h,
-                                       [&]() { return layerInfo->mutable_size(); });
-
-    LayerProtoHelper::writeToProto(state.crop_legacy, [&]() { return layerInfo->mutable_crop(); });
-    layerInfo->set_corner_radius(getRoundedCornerState().radius);
-
-    layerInfo->set_is_opaque(isOpaque(state));
-    layerInfo->set_invalidate(contentDirty);
-
-    // XXX (b/79210409) mCurrentDataSpace is not protected
-    layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
-
-    layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
-    LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
-    LayerProtoHelper::writeToProto(state.color,
-                                   [&]() { return layerInfo->mutable_requested_color(); });
-    layerInfo->set_flags(state.flags);
-
-    LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
-    LayerProtoHelper::writeToProto(requestedTransform, layerInfo->mutable_requested_transform());
-
-    auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
-    if (parent != nullptr) {
-        layerInfo->set_parent(parent->sequence);
-    } else {
-        layerInfo->set_parent(-1);
-    }
-
-    auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
-    if (zOrderRelativeOf != nullptr) {
-        layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
-    } else {
-        layerInfo->set_z_order_relative_of(-1);
-    }
-
-    auto buffer = mActiveBuffer;
-    if (buffer != nullptr) {
-        LayerProtoHelper::writeToProto(buffer,
-                                       [&]() { return layerInfo->mutable_active_buffer(); });
-        LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
-                                       layerInfo->mutable_buffer_transform());
-    }
-
-    layerInfo->set_queued_frames(getQueuedFrameCount());
-    layerInfo->set_refresh_pending(isBufferLatched());
-    layerInfo->set_curr_frame(mCurrentFrameNumber);
-    layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
-
-    for (const auto& pendingState : mPendingStates) {
-        auto barrierLayer = pendingState.barrierLayer_legacy.promote();
-        if (barrierLayer != nullptr) {
-            BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
-            barrierLayerProto->set_id(barrierLayer->sequence);
-            barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
+        for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
+            sp<Layer> strongRelative = weakRelative.promote();
+            if (strongRelative != nullptr) {
+                layerInfo->add_relatives(strongRelative->sequence);
+            }
         }
+
+        LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
+                                       [&]() { return layerInfo->mutable_transparent_region(); });
+        LayerProtoHelper::writeToProto(visibleRegion,
+                                       [&]() { return layerInfo->mutable_visible_region(); });
+        LayerProtoHelper::writeToProto(surfaceDamageRegion,
+                                       [&]() { return layerInfo->mutable_damage_region(); });
+
+        layerInfo->set_layer_stack(getLayerStack());
+        layerInfo->set_z(state.z);
+
+        LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
+                                               [&]() { return layerInfo->mutable_position(); });
+
+        LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(),
+                                               [&]() {
+                                                   return layerInfo->mutable_requested_position();
+                                               });
+
+        LayerProtoHelper::writeSizeToProto(state.active_legacy.w, state.active_legacy.h,
+                                           [&]() { return layerInfo->mutable_size(); });
+
+        LayerProtoHelper::writeToProto(state.crop_legacy,
+                                       [&]() { return layerInfo->mutable_crop(); });
+        layerInfo->set_corner_radius(getRoundedCornerState().radius);
+
+        layerInfo->set_is_opaque(isOpaque(state));
+        layerInfo->set_invalidate(contentDirty);
+
+        // XXX (b/79210409) mCurrentDataSpace is not protected
+        layerInfo->set_dataspace(
+                dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
+
+        layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
+        LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
+        LayerProtoHelper::writeToProto(state.color,
+                                       [&]() { return layerInfo->mutable_requested_color(); });
+        layerInfo->set_flags(state.flags);
+
+        LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
+        LayerProtoHelper::writeToProto(requestedTransform,
+                                       layerInfo->mutable_requested_transform());
+
+        auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
+        if (parent != nullptr) {
+            layerInfo->set_parent(parent->sequence);
+        } else {
+            layerInfo->set_parent(-1);
+        }
+
+        auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
+        if (zOrderRelativeOf != nullptr) {
+            layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
+        } else {
+            layerInfo->set_z_order_relative_of(-1);
+        }
+
+        auto buffer = mActiveBuffer;
+        if (buffer != nullptr) {
+            LayerProtoHelper::writeToProto(buffer,
+                                           [&]() { return layerInfo->mutable_active_buffer(); });
+            LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
+                                           layerInfo->mutable_buffer_transform());
+        }
+
+        layerInfo->set_queued_frames(getQueuedFrameCount());
+        layerInfo->set_refresh_pending(isBufferLatched());
+        layerInfo->set_curr_frame(mCurrentFrameNumber);
+        layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
+
+        for (const auto& pendingState : mPendingStates) {
+            auto barrierLayer = pendingState.barrierLayer_legacy.promote();
+            if (barrierLayer != nullptr) {
+                BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
+                barrierLayerProto->set_id(barrierLayer->sequence);
+                barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
+            }
+        }
+        LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
     }
 
-    auto protoMap = layerInfo->mutable_metadata();
-    for (const auto& entry : state.metadata.mMap) {
-        (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
+    if (traceFlags & SurfaceTracing::TRACE_INPUT) {
+        LayerProtoHelper::writeToProto(state.inputInfo, state.touchableRegionCrop,
+                                       [&]() { return layerInfo->mutable_input_window_info(); });
     }
-    LayerProtoHelper::writeToProto(mEffectiveTransform, layerInfo->mutable_effective_transform());
-    LayerProtoHelper::writeToProto(mSourceBounds,
-                                   [&]() { return layerInfo->mutable_source_bounds(); });
-    LayerProtoHelper::writeToProto(mScreenBounds,
-                                   [&]() { return layerInfo->mutable_screen_bounds(); });
-    LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
+
+    if (traceFlags & SurfaceTracing::TRACE_EXTRA) {
+        auto protoMap = layerInfo->mutable_metadata();
+        for (const auto& entry : state.metadata.mMap) {
+            (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
+        }
+        LayerProtoHelper::writeToProto(mEffectiveTransform,
+                                       layerInfo->mutable_effective_transform());
+        LayerProtoHelper::writeToProto(mSourceBounds,
+                                       [&]() { return layerInfo->mutable_source_bounds(); });
+        LayerProtoHelper::writeToProto(mScreenBounds,
+                                       [&]() { return layerInfo->mutable_screen_bounds(); });
+    }
 }
 
-void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice) {
+void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
+                         uint32_t traceFlags) {
     auto outputLayer = findOutputLayerForDisplay(displayDevice);
     if (!outputLayer) {
         return;
     }
 
-    writeToProto(layerInfo, LayerVector::StateSet::Drawing);
+    writeToProto(layerInfo, LayerVector::StateSet::Drawing, traceFlags);
 
     const auto& compositionState = outputLayer->getState();
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 89063da..b9dc7ec 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -433,10 +433,11 @@
 
     bool isRemovedFromCurrentState() const;
 
-    void writeToProto(LayerProto* layerInfo,
-                      LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
+    void writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet,
+                      uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
 
-    void writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice);
+    void writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
+                      uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
 
     virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
     virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
@@ -451,13 +452,13 @@
 
     virtual void setPostTime(nsecs_t /*postTime*/) {}
     virtual void setDesiredPresentTime(nsecs_t /*desiredPresentTime*/) {}
+    virtual RoundedCornerState getRoundedCornerStateInternal(const FloatRect bounds) const;
 
 protected:
     virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                                     bool useIdentityTransform, Region& clearRegion,
                                     const bool supportProtectedContent,
                                     renderengine::LayerSettings& layer);
-
 public:
     /*
      * compositionengine::LayerFE overrides
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index c25c418..c94e439 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -119,5 +119,41 @@
     }
 }
 
+void LayerProtoHelper::writeToProto(
+        const InputWindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds,
+        std::function<InputWindowInfoProto*()> getInputWindowInfoProto) {
+    if (inputInfo.token == nullptr) {
+        return;
+    }
+
+    InputWindowInfoProto* proto = getInputWindowInfoProto();
+    proto->set_layout_params_flags(inputInfo.layoutParamsFlags);
+    proto->set_layout_params_type(inputInfo.layoutParamsType);
+
+    LayerProtoHelper::writeToProto({inputInfo.frameLeft, inputInfo.frameTop, inputInfo.frameRight,
+                                    inputInfo.frameBottom},
+                                   [&]() { return proto->mutable_frame(); });
+    LayerProtoHelper::writeToProto(inputInfo.touchableRegion,
+                                   [&]() { return proto->mutable_touchable_region(); });
+
+    proto->set_surface_inset(inputInfo.surfaceInset);
+    proto->set_visible(inputInfo.visible);
+    proto->set_can_receive_keys(inputInfo.canReceiveKeys);
+    proto->set_has_focus(inputInfo.hasFocus);
+    proto->set_has_wallpaper(inputInfo.hasWallpaper);
+
+    proto->set_global_scale_factor(inputInfo.globalScaleFactor);
+    proto->set_window_x_scale(inputInfo.windowXScale);
+    proto->set_window_y_scale(inputInfo.windowYScale);
+    proto->set_replace_touchable_region_with_crop(inputInfo.replaceTouchableRegionWithCrop);
+    auto cropLayer = touchableRegionBounds.promote();
+    if (cropLayer != nullptr) {
+        proto->set_crop_layer_id(cropLayer->sequence);
+        LayerProtoHelper::writeToProto(cropLayer->getScreenBounds(
+                                               false /* reduceTransparentRegion */),
+                                       [&]() { return proto->mutable_touchable_region_crop(); });
+    }
+}
+
 } // namespace surfaceflinger
 } // namespace android
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index dca9a5e..1754a3f 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -16,6 +16,8 @@
 
 #include <layerproto/LayerProtoHeader.h>
 
+#include <Layer.h>
+#include <input/InputWindow.h>
 #include <math/vec4.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/Rect.h>
@@ -38,6 +40,9 @@
     static void writeToProto(const ui::Transform& transform, TransformProto* transformProto);
     static void writeToProto(const sp<GraphicBuffer>& buffer,
                              std::function<ActiveBufferProto*()> getActiveBufferProto);
+    static void writeToProto(const InputWindowInfo& inputInfo,
+                             const wp<Layer>& touchableRegionBounds,
+                             std::function<InputWindowInfoProto*()> getInputWindowInfoProto);
 };
 
 } // namespace surfaceflinger
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
new file mode 100644
index 0000000..e70bfe4
--- /dev/null
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RefreshRateOverlay.h"
+#include "Client.h"
+#include "Layer.h"
+
+namespace android {
+
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
+RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger)
+      : mFlinger(flinger), mClient(new Client(&mFlinger)) {
+    createLayer();
+}
+
+bool RefreshRateOverlay::createLayer() {
+    const status_t ret =
+            mFlinger.createLayer(String8("RefreshRateOverlay"), mClient, 0, 0,
+                                 PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor,
+                                 LayerMetadata(), &mIBinder, &mGbp, &mLayer);
+    if (ret) {
+        ALOGE("failed to color layer");
+        return false;
+    }
+
+    mLayer = mClient->getLayerUser(mIBinder);
+    mLayer->setCrop_legacy(Rect(0, 0, 200, 100), true);
+    mLayer->setLayer(INT32_MAX - 2);
+
+    return true;
+}
+
+void RefreshRateOverlay::changeRefreshRate(RefreshRateType type) {
+    const half3& color = (type == RefreshRateType::PERFORMANCE) ? GREEN : RED;
+    mLayer->setColor(color);
+    mFlinger.setTransactionFlags(eTransactionMask);
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
new file mode 100644
index 0000000..ce29bc3
--- /dev/null
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
+class RefreshRateOverlay {
+public:
+    RefreshRateOverlay(SurfaceFlinger& flinger);
+
+    void changeRefreshRate(RefreshRateType type);
+
+private:
+    bool createLayer();
+
+    SurfaceFlinger& mFlinger;
+    sp<Client> mClient;
+    sp<Layer> mLayer;
+    sp<IBinder> mIBinder;
+    sp<IGraphicBufferProducer> mGbp;
+
+    const half3 RED = half3(1.0f, 0.0f, 0.0f);
+    const half3 GREEN = half3(0.0f, 1.0f, 0.0f);
+};
+
+}; // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 6599f9e..a2a6bd8 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -211,13 +211,14 @@
             const nsecs_t numPeriodsSinceReference = baseTime / mPeriod;
             const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod;
             const nsecs_t phaseCorrection = mPhase + listener.mPhase;
-            const nsecs_t predictedLastEventTime = predictedReference + phaseCorrection;
-            if (predictedLastEventTime >= now) {
-                // Make sure that the last event time does not exceed the current time.
-                // If it would, then back the last event time by a period.
-                listener.mLastEventTime = predictedLastEventTime - mPeriod;
-            } else {
-                listener.mLastEventTime = predictedLastEventTime;
+            listener.mLastEventTime = predictedReference + phaseCorrection;
+            // If we're very close in time to the predicted last event time,
+            // then we need to back up the last event time so that we can
+            // attempt to fire an event immediately.
+            //
+            // Otherwise, keep the last event time that we predicted.
+            if (isShorterThanPeriod(now - listener.mLastEventTime)) {
+                listener.mLastEventTime -= mPeriod;
             }
         } else {
             listener.mLastEventTime = now + mPhase - mWakeupLatency;
@@ -314,7 +315,7 @@
 
     // Sanity check that the duration is close enough in length to a period without
     // falling into double-rate vsyncs.
-    bool isCloseToPeriod(nsecs_t duration) {
+    bool isShorterThanPeriod(nsecs_t duration) {
         // Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
         return duration < (3 * mPeriod) / 5;
     }
@@ -330,7 +331,7 @@
             nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);
 
             if (t < now) {
-                if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) {
+                if (isShorterThanPeriod(now - eventListener.mLastCallbackTime)) {
                     eventListener.mLastEventTime = t;
                     eventListener.mLastCallbackTime = now;
                     ALOGV("[%s] [%s] Skipping event due to model error", mName,
@@ -391,7 +392,7 @@
 
         // Check that it's been slightly more than half a period since the last
         // event so that we don't accidentally fall into double-rate vsyncs
-        if (isCloseToPeriod(t - listener.mLastEventTime)) {
+        if (isShorterThanPeriod(t - listener.mLastEventTime)) {
             t += mPeriod;
             ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
         }
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index cbcc031..1aa6ade 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -57,16 +57,23 @@
     }
     ~RefreshRateConfigs() = default;
 
-    const std::unordered_map<RefreshRateType, RefreshRate>& getRefreshRates() {
+    const std::map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() {
         return mRefreshRates;
     }
-    const RefreshRate& getRefreshRate(RefreshRateType type) { return mRefreshRates[type]; }
+    std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) {
+        const auto& refreshRate = mRefreshRates.find(type);
+        if (refreshRate != mRefreshRates.end()) {
+            return refreshRate->second;
+        }
+        return nullptr;
+    }
 
 private:
     void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
         // This is the rate that HWC encapsulates right now when the device is in DOZE mode.
         mRefreshRates.emplace(RefreshRateType::POWER_SAVING,
-                              RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0});
+                              std::make_shared<RefreshRate>(
+                                      RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}));
 
         if (configs.size() < 1) {
             ALOGE("Device does not have valid configs. Config size is 0.");
@@ -90,9 +97,10 @@
         if (vsyncPeriod != 0) {
             const float fps = 1e9 / vsyncPeriod;
             mRefreshRates.emplace(RefreshRateType::DEFAULT,
-                                  RefreshRate{configIdToVsyncPeriod[0].first,
-                                              base::StringPrintf("%2.ffps", fps),
-                                              static_cast<uint32_t>(fps)});
+                                  std::make_shared<RefreshRate>(
+                                          RefreshRate{configIdToVsyncPeriod[0].first,
+                                                      base::StringPrintf("%2.ffps", fps),
+                                                      static_cast<uint32_t>(fps)}));
         }
 
         if (configs.size() < 2) {
@@ -105,13 +113,14 @@
         if (vsyncPeriod != 0) {
             const float fps = 1e9 / vsyncPeriod;
             mRefreshRates.emplace(RefreshRateType::PERFORMANCE,
-                                  RefreshRate{configIdToVsyncPeriod[1].first,
-                                              base::StringPrintf("%2.ffps", fps),
-                                              static_cast<uint32_t>(fps)});
+                                  std::make_shared<RefreshRate>(
+                                          RefreshRate{configIdToVsyncPeriod[1].first,
+                                                      base::StringPrintf("%2.ffps", fps),
+                                                      static_cast<uint32_t>(fps)}));
         }
     }
 
-    std::unordered_map<RefreshRateType, RefreshRate> mRefreshRates;
+    std::map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates;
 };
 
 } // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index 2491081..ff63faf 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -85,10 +85,13 @@
         std::unordered_map<std::string, int64_t> totalTime;
         for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) {
             int64_t totalTimeForConfig = 0;
-            if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) {
-                totalTimeForConfig = mConfigModesTotalTime.at(config.configId);
+            if (!config) {
+                continue;
             }
-            totalTime[config.name] = totalTimeForConfig;
+            if (mConfigModesTotalTime.find(config->configId) != mConfigModesTotalTime.end()) {
+                totalTimeForConfig = mConfigModesTotalTime.at(config->configId);
+            }
+            totalTime[config->name] = totalTimeForConfig;
         }
         return totalTime;
     }
@@ -124,8 +127,11 @@
 
         mConfigModesTotalTime[mode] += timeElapsedMs;
         for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) {
-            if (config.configId == mode) {
-                mTimeStats->recordRefreshRate(config.fps, timeElapsed);
+            if (!config) {
+                continue;
+            }
+            if (config->configId == mode) {
+                mTimeStats->recordRefreshRate(config->fps, timeElapsed);
             }
         }
     }
@@ -147,7 +153,7 @@
     // Aggregate refresh rate statistics for telemetry.
     std::shared_ptr<TimeStats> mTimeStats;
 
-    int64_t mCurrentConfigMode = 0;
+    int64_t mCurrentConfigMode = SCREEN_OFF_CONFIG_ID;
     int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
 
     std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4c4a29b..f7e4afd 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -84,6 +84,7 @@
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
 #include "NativeWindowSurface.h"
+#include "RefreshRateOverlay.h"
 #include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
 #include "SurfaceInterceptor.h"
@@ -128,8 +129,6 @@
 using ui::Hdr;
 using ui::RenderIntent;
 
-using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
-
 namespace {
 
 #pragma clang diagnostic push
@@ -592,10 +591,11 @@
         const auto displayId = getInternalDisplayIdLocked();
         LOG_ALWAYS_FATAL_IF(!displayId);
 
-        const auto performanceRefreshRate =
+        const auto& performanceRefreshRate =
                 mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
 
-        if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
+        if (performanceRefreshRate &&
+            isConfigAllowed(*displayId, performanceRefreshRate->configId)) {
             setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None);
         } else {
             setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None);
@@ -738,6 +738,7 @@
     mRefreshRateStats =
             std::make_unique<scheduler::RefreshRateStats>(mRefreshRateConfigs[*display->getId()],
                                                           mTimeStats);
+    mRefreshRateStats->setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId()));
 
     ALOGV("Done initializing");
 }
@@ -940,19 +941,18 @@
     return display->getActiveConfig();
 }
 
-void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
-                                            Scheduler::ConfigEvent event) {
+void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
     ATRACE_CALL();
 
     // Lock is acquired by setRefreshRateTo.
-    const auto display = getDisplayDeviceLocked(displayToken);
+    const auto display = getDisplayDeviceLocked(info.displayToken);
     if (!display) {
-        ALOGE("Attempt to set active config %d for invalid display token %p", mode,
-              displayToken.get());
+        ALOGE("Attempt to set active config %d for invalid display token %p", info.configId,
+              info.displayToken.get());
         return;
     }
     if (display->isVirtual()) {
-        ALOGW("Attempt to set active config %d for virtual display", mode);
+        ALOGW("Attempt to set active config %d for virtual display", info.configId);
         return;
     }
     int currentDisplayPowerMode = display->getPowerMode();
@@ -965,8 +965,9 @@
     // config twice. However event generation config might have changed so we need to update it
     // accordingly
     std::lock_guard<std::mutex> lock(mActiveConfigLock);
-    const Scheduler::ConfigEvent desiredConfig = mDesiredActiveConfig.event | event;
-    mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken, desiredConfig};
+    const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event;
+    mDesiredActiveConfig = info;
+    mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig;
 
     if (!mDesiredActiveConfigChanged) {
         // This is the first time we set the desired
@@ -977,6 +978,10 @@
     }
     mDesiredActiveConfigChanged = true;
     ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+
+    if (mRefreshRateOverlay) {
+        mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
+    }
 }
 
 status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
@@ -1039,6 +1044,7 @@
         // on both cases there is nothing left to do
         std::lock_guard<std::mutex> lock(mActiveConfigLock);
         mScheduler->pauseVsyncCallback(mAppConnectionHandle, false);
+        mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
         mDesiredActiveConfigChanged = false;
         ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
         return false;
@@ -1470,19 +1476,26 @@
     LOG_ALWAYS_FATAL_IF(!displayId);
     const auto displayToken = getInternalDisplayTokenLocked();
 
-    auto desiredConfigId = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate).configId;
-    const auto display = getDisplayDeviceLocked(displayToken);
-    if (desiredConfigId == display->getActiveConfig()) {
+    const auto& refreshRateConfig = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate);
+    if (!refreshRateConfig) {
+        ALOGV("Skipping refresh rate change request for unsupported rate.");
         return;
     }
 
+    const int desiredConfigId = refreshRateConfig->configId;
+
     if (!isConfigAllowed(*displayId, desiredConfigId)) {
         ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId);
         return;
     }
 
+    const auto display = getDisplayDeviceLocked(displayToken);
+    if (desiredConfigId == display->getActiveConfig()) {
+        return;
+    }
+
     mPhaseOffsets->setRefreshRateType(refreshRate);
-    setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event);
+    setDesiredActiveConfig({refreshRate, desiredConfigId, getInternalDisplayTokenLocked(), event});
 }
 
 void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -2510,6 +2523,9 @@
                 state.displayName = info->name;
                 mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
                 mInterceptor->saveDisplayCreation(state);
+                // TODO(b/123715322): Removes the per-display state that was added to the scheduler.
+                mRefreshRateConfigs[info->id] = std::make_shared<scheduler::RefreshRateConfigs>(
+                        getHwComposer().getConfigs(info->id));
             }
         } else {
             ALOGV("Removing display %s", to_string(info->id).c_str());
@@ -2521,6 +2537,7 @@
                 mCurrentState.displays.removeItemsAt(index);
             }
             mPhysicalDisplayTokens.erase(info->id);
+            mRefreshRateConfigs.erase(info->id);
         }
 
         processDisplayChangesLocked();
@@ -2906,13 +2923,13 @@
 }
 
 void SurfaceFlinger::updateInputWindowInfo() {
-    Vector<InputWindowInfo> inputHandles;
+    std::vector<InputWindowInfo> inputHandles;
 
     mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
         if (layer->hasInput()) {
             // When calculating the screen bounds we ignore the transparent region since it may
             // result in an unwanted offset.
-            inputHandles.add(layer->fillInputInfo());
+            inputHandles.push_back(layer->fillInputInfo());
         }
     });
 
@@ -3508,13 +3525,15 @@
         auto& [applyToken, transactionQueue] = *it;
 
         while (!transactionQueue.empty()) {
-            const auto& [states, displays, flags, desiredPresentTime, postTime, privileged] =
-                    transactionQueue.front();
+            const auto&
+                    [states, displays, flags, desiredPresentTime, uncacheBuffer, listenerCallbacks,
+                     postTime, privileged] = transactionQueue.front();
             if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
                 break;
             }
             applyTransactionState(states, displays, flags, mPendingInputWindowCommands,
-                                  desiredPresentTime, postTime, privileged);
+                                  desiredPresentTime, uncacheBuffer, listenerCallbacks, postTime,
+                                  privileged, /*isMainThread*/ true);
             transactionQueue.pop();
         }
 
@@ -3571,7 +3590,9 @@
                                          const Vector<DisplayState>& displays, uint32_t flags,
                                          const sp<IBinder>& applyToken,
                                          const InputWindowCommands& inputWindowCommands,
-                                         int64_t desiredPresentTime) {
+                                         int64_t desiredPresentTime,
+                                         const cached_buffer_t& uncacheBuffer,
+                                         const std::vector<ListenerCallbacks>& listenerCallbacks) {
     ATRACE_CALL();
 
     const int64_t postTime = systemTime();
@@ -3588,20 +3609,24 @@
     if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
         !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
         mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
-                                               postTime, privileged);
+                                               uncacheBuffer, listenerCallbacks, postTime,
+                                               privileged);
         setTransactionFlags(eTransactionNeeded);
         return;
     }
 
     applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime,
-                          postTime, privileged);
+                          uncacheBuffer, listenerCallbacks, postTime, privileged);
 }
 
 void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states,
                                            const Vector<DisplayState>& displays, uint32_t flags,
                                            const InputWindowCommands& inputWindowCommands,
-                                           const int64_t desiredPresentTime, const int64_t postTime,
-                                           bool privileged) {
+                                           const int64_t desiredPresentTime,
+                                           const cached_buffer_t& uncacheBuffer,
+                                           const std::vector<ListenerCallbacks>& listenerCallbacks,
+                                           const int64_t postTime, bool privileged,
+                                           bool isMainThread) {
     uint32_t transactionFlags = 0;
 
     if (flags & eAnimation) {
@@ -3626,7 +3651,15 @@
 
     uint32_t clientStateFlags = 0;
     for (const ComposerState& state : states) {
-        clientStateFlags |= setClientStateLocked(state, desiredPresentTime, postTime, privileged);
+        clientStateFlags |= setClientStateLocked(state, desiredPresentTime, listenerCallbacks,
+                                                 postTime, privileged);
+    }
+
+    // In case the client has sent a Transaction that should receive callbacks but without any
+    // SurfaceControls that should be included in the callback, send the listener and callbackIds
+    // to the callback thread so it can send an empty callback
+    for (const auto& [listener, callbackIds] : listenerCallbacks) {
+        mTransactionCompletedThread.addCallback(listener, callbackIds);
     }
     // If the state doesn't require a traversal and there are callbacks, send them now
     if (!(clientStateFlags & eTraversalNeeded)) {
@@ -3636,6 +3669,10 @@
 
     transactionFlags |= addInputWindowCommands(inputWindowCommands);
 
+    if (uncacheBuffer.token) {
+        BufferStateLayerCache::getInstance().erase(uncacheBuffer.token, uncacheBuffer.cacheId);
+    }
+
     // If a synchronous transaction is explicitly requested without any changes, force a transaction
     // anyway. This can be used as a flush mechanism for previous async transactions.
     // Empty animation transaction can be used to simulate back-pressure, so also force a
@@ -3665,7 +3702,12 @@
         }
 
         mPendingSyncInputWindows = mPendingInputWindowCommands.syncInputWindows;
-        while (mTransactionPending || mPendingSyncInputWindows) {
+
+        // applyTransactionState can be called by either the main SF thread or by
+        // another process through setTransactionState.  While a given process may wish
+        // to wait on synchronous transactions, the main SF thread should never
+        // be blocked.  Therefore, we only wait if isMainThread is false.
+        while (!isMainThread && (mTransactionPending || mPendingSyncInputWindows)) {
             status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
             if (CC_UNLIKELY(err != NO_ERROR)) {
                 // just in case something goes wrong in SF, return to the
@@ -3738,9 +3780,10 @@
     return true;
 }
 
-uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState,
-                                              int64_t desiredPresentTime, int64_t postTime,
-                                              bool privileged) {
+uint32_t SurfaceFlinger::setClientStateLocked(
+        const ComposerState& composerState, int64_t desiredPresentTime,
+        const std::vector<ListenerCallbacks>& listenerCallbacks, int64_t postTime,
+        bool privileged) {
     const layer_state_t& s = composerState.state;
     sp<Client> client(static_cast<Client*>(composerState.client.get()));
 
@@ -3966,22 +4009,26 @@
         }
     }
     std::vector<sp<CallbackHandle>> callbackHandles;
-    if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
+    if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!listenerCallbacks.empty())) {
         mTransactionCompletedThread.run();
-        for (const auto& [listener, callbackIds] : s.listenerCallbacks) {
+        for (const auto& [listener, callbackIds] : listenerCallbacks) {
             callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
         }
     }
-
-    if (what & layer_state_t::eBufferChanged) {
-        // Add the new buffer to the cache. This should always come before eCachedBufferChanged.
-        BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.bufferId,
+    bool bufferChanged = what & layer_state_t::eBufferChanged;
+    bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
+    sp<GraphicBuffer> buffer;
+    if (bufferChanged && cacheIdChanged) {
+        BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.cacheId,
                                                  s.buffer);
+        buffer = s.buffer;
+    } else if (cacheIdChanged) {
+        buffer = BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
+                                                          s.cachedBuffer.cacheId);
+    } else if (bufferChanged) {
+        buffer = s.buffer;
     }
-    if (what & layer_state_t::eCachedBufferChanged) {
-        sp<GraphicBuffer> buffer =
-                BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
-                                                         s.cachedBuffer.bufferId);
+    if (buffer) {
         if (layer->setBuffer(buffer)) {
             flags |= eTraversalNeeded;
             layer->setPostTime(postTime);
@@ -4225,7 +4272,7 @@
     d.width = 0;
     d.height = 0;
     displays.add(d);
-    setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1);
+    setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, {});
 
     setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
 
@@ -4639,13 +4686,14 @@
     result.append("\n");
 }
 
-LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet) const {
+LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet,
+                                          uint32_t traceFlags) const {
     LayersProto layersProto;
     const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
     const State& state = useDrawing ? mDrawingState : mCurrentState;
     state.traverseInZOrder([&](Layer* layer) {
         LayerProto* layerProto = layersProto.add_layers();
-        layer->writeToProto(layerProto, stateSet);
+        layer->writeToProto(layerProto, stateSet, traceFlags);
     });
 
     return layersProto;
@@ -4988,9 +5036,9 @@
         code == IBinder::SYSPROPS_TRANSACTION) {
         return OK;
     }
-    // Numbers from 1000 to 1032 are currently use for backdoors. The code
+    // Numbers from 1000 to 1034 are currently used for backdoors. The code
     // in onTransact verifies that the user is root, and has access to use SF.
-    if (code >= 1000 && code <= 1032) {
+    if (code >= 1000 && code <= 1034) {
         ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
         return OK;
     }
@@ -5298,6 +5346,26 @@
                 mDebugEnableProtectedContent = n;
                 return NO_ERROR;
             }
+            // Set trace flags
+            case 1033: {
+                n = data.readUint32();
+                ALOGD("Updating trace flags to 0x%x", n);
+                mTracing.setTraceFlags(n);
+                reply->writeInt32(NO_ERROR);
+                return NO_ERROR;
+            }
+            case 1034: {
+                // TODO(b/129297325): expose this via developer menu option
+                n = data.readInt32();
+                if (n && !mRefreshRateOverlay) {
+                    std::lock_guard<std::mutex> lock(mActiveConfigLock);
+                    mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
+                    mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
+                } else if (!n) {
+                    mRefreshRateOverlay.reset();
+                }
+                return NO_ERROR;
+            }
         }
     }
     return err;
@@ -5765,29 +5833,14 @@
         mAllowedConfigs[*displayId] = std::move(allowedConfigs);
     }
 
-    // make sure that the current config is still allowed
-    int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId);
-    if (!isConfigAllowed(*displayId, currentConfigIndex)) {
-        for (const auto& [type, config] : mRefreshRateConfigs[*displayId]->getRefreshRates()) {
-            if (isConfigAllowed(*displayId, config.configId)) {
-                // TODO: we switch to the first allowed config. In the future
-                // we may want to enhance this logic to pick a similar config
-                // to the current one
-                ALOGV("Old config is not allowed - switching to config %d", config.configId);
-                setDesiredActiveConfig(displayToken, config.configId,
-                                       Scheduler::ConfigEvent::Changed);
-                break;
-            }
-        }
-    }
-
-    // If idle timer and fps detection are disabled and we are in RefreshRateType::DEFAULT,
-    // there is no trigger to move to RefreshRateType::PERFORMANCE, even if it is an allowed.
-    if (!mScheduler->isIdleTimerEnabled() && !mUseSmart90ForVideo) {
-        const auto performanceRefreshRate =
-                mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
-        if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
-            setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed);
+    // Set the highest allowed config by iterating backwards on available refresh rates
+    const auto& refreshRates = mRefreshRateConfigs[*displayId]->getRefreshRates();
+    for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
+        if (iter->second && isConfigAllowed(*displayId, iter->second->configId)) {
+            ALOGV("switching to config %d", iter->second->configId);
+            setDesiredActiveConfig({iter->first, iter->second->configId, displayToken,
+                                    Scheduler::ConfigEvent::Changed});
+            break;
         }
     }
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0d39cb5..141af73 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -90,6 +90,8 @@
 
 namespace android {
 
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
 // ---------------------------------------------------------------------------
 
 class Client;
@@ -102,6 +104,7 @@
 class IInputFlinger;
 class InjectVSyncSource;
 class Layer;
+class RefreshRateOverlay;
 class Surface;
 class SurfaceFlingerBE;
 class TimeStats;
@@ -366,6 +369,7 @@
     friend class BufferQueueLayer;
     friend class BufferStateLayer;
     friend class MonitoredProducer;
+    friend class RefreshRateOverlay;
     friend class RegionSamplingThread;
     friend class SurfaceTracing;
 
@@ -431,7 +435,8 @@
                              const Vector<DisplayState>& displays, uint32_t flags,
                              const sp<IBinder>& applyToken,
                              const InputWindowCommands& inputWindowCommands,
-                             int64_t desiredPresentTime) override;
+                             int64_t desiredPresentTime, const cached_buffer_t& uncacheBuffer,
+                             const std::vector<ListenerCallbacks>& listenerCallbacks) override;
     void bootFinished() override;
     bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& bufferProducer) const override;
@@ -527,11 +532,30 @@
     void signalLayerUpdate();
     void signalRefresh();
 
+    struct ActiveConfigInfo {
+        RefreshRateType type;
+        int configId;
+        sp<IBinder> displayToken;
+        Scheduler::ConfigEvent event;
+
+        bool operator!=(const ActiveConfigInfo& other) const {
+            if (type != other.type) {
+                return true;
+            }
+            if (configId != other.configId) {
+                return true;
+            }
+            if (displayToken != other.displayToken) {
+                return true;
+            }
+            return (event != other.event);
+        }
+    };
+
     // called on the main thread in response to initializeDisplays()
     void onInitializeDisplays() REQUIRES(mStateLock);
     // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
-    void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
-                                Scheduler::ConfigEvent event) REQUIRES(mStateLock);
+    void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
     // Once HWC has returned the present fence, this sets the active config and a new refresh
     // rate in SF. It also triggers HWC vsync.
     void setActiveConfigInternal() REQUIRES(mStateLock);
@@ -577,8 +601,11 @@
     void applyTransactionState(const Vector<ComposerState>& state,
                                const Vector<DisplayState>& displays, uint32_t flags,
                                const InputWindowCommands& inputWindowCommands,
-                               const int64_t desiredPresentTime, const int64_t postTime,
-                               bool privileged) REQUIRES(mStateLock);
+                               const int64_t desiredPresentTime,
+                               const cached_buffer_t& uncacheBuffer,
+                               const std::vector<ListenerCallbacks>& listenerCallbacks,
+                               const int64_t postTime, bool privileged, bool isMainThread = false)
+            REQUIRES(mStateLock);
     bool flushTransactionQueues();
     uint32_t getTransactionFlags(uint32_t flags);
     uint32_t peekTransactionFlags();
@@ -591,6 +618,7 @@
     bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
                                        const Vector<ComposerState>& states);
     uint32_t setClientStateLocked(const ComposerState& composerState, int64_t desiredPresentTime,
+                                  const std::vector<ListenerCallbacks>& listenerCallbacks,
                                   int64_t postTime, bool privileged) REQUIRES(mStateLock);
     uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
     uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
@@ -813,8 +841,7 @@
 
     // Sets the refresh rate by switching active configs, if they are available for
     // the desired refresh rate.
-    void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType,
-                          Scheduler::ConfigEvent event) REQUIRES(mStateLock);
+    void setRefreshRateTo(RefreshRateType, Scheduler::ConfigEvent event) REQUIRES(mStateLock);
 
     bool isConfigAllowed(const DisplayId& displayId, int32_t config);
 
@@ -895,7 +922,8 @@
     void dumpBufferingStats(std::string& result) const;
     void dumpDisplayIdentificationData(std::string& result) const;
     void dumpWideColorInfo(std::string& result) const;
-    LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
+    LayersProto dumpProtoInfo(LayerVector::StateSet stateSet,
+                              uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
     void withTracingLock(std::function<void()> operation) REQUIRES(mStateLock);
     LayersProto dumpVisibleLayersProtoInfo(const sp<DisplayDevice>& display) const;
 
@@ -1058,11 +1086,15 @@
     struct TransactionState {
         TransactionState(const Vector<ComposerState>& composerStates,
                          const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
-                         int64_t desiredPresentTime, int64_t postTime, bool privileged)
+                         int64_t desiredPresentTime, const cached_buffer_t& uncacheBuffer,
+                         const std::vector<ListenerCallbacks>& listenerCallbacks, int64_t postTime,
+                         bool privileged)
               : states(composerStates),
                 displays(displayStates),
                 flags(transactionFlags),
                 desiredPresentTime(desiredPresentTime),
+                buffer(uncacheBuffer),
+                callback(listenerCallbacks),
                 postTime(postTime),
                 privileged(privileged) {}
 
@@ -1070,6 +1102,8 @@
         Vector<DisplayState> displays;
         uint32_t flags;
         const int64_t desiredPresentTime;
+        cached_buffer_t buffer;
+        std::vector<ListenerCallbacks> callback;
         const int64_t postTime;
         bool privileged;
     };
@@ -1128,18 +1162,6 @@
     std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs
             GUARDED_BY(mAllowedConfigsLock);
 
-    struct ActiveConfigInfo {
-        int configId;
-        sp<IBinder> displayToken;
-        Scheduler::ConfigEvent event;
-
-        bool operator!=(const ActiveConfigInfo& other) const {
-            if (configId != other.configId) {
-                return true;
-            }
-            return (displayToken != other.displayToken);
-        }
-    };
     std::mutex mActiveConfigLock;
     // This bit is set once we start setting the config. We read from this bit during the
     // process. If at the end, this bit is different than mDesiredActiveConfig, we restart
@@ -1166,6 +1188,8 @@
     sp<SetInputWindowsListener> mSetInputWindowsListener;
     bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
     Hwc2::impl::PowerAdvisor mPowerAdvisor;
+
+    std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
 };
 }; // namespace android
 
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index db78f1d..c4ab066 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -28,46 +28,56 @@
 
 namespace android {
 
-void SurfaceTracing::mainLoop() {
-    bool enabled = true;
-    // Upon activation, logs the first frame
-    traceLayers("tracing.enable");
-    do {
-        std::unique_lock<std::mutex> sfLock(mFlinger.mDrawingStateLock);
-        mConditionalVariable.wait(sfLock);
-        LayersTraceProto entry = traceLayersLocked(mWhere);
-        sfLock.unlock();
-        {
-            std::scoped_lock bufferLock(mTraceLock);
-            mBuffer.emplace(std::move(entry));
-            if (mWriteToFile) {
-                writeProtoFileLocked();
-                mWriteToFile = false;
-            }
+SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger)
+      : mFlinger(flinger), mSfLock(flinger.mDrawingStateLock) {}
 
-            enabled = mEnabled;
-        }
-    } while (enabled);
+void SurfaceTracing::mainLoop() {
+    addFirstEntry();
+    bool enabled = true;
+    while (enabled) {
+        LayersTraceProto entry = traceWhenNotified();
+        enabled = addTraceToBuffer(entry);
+    }
 }
 
-void SurfaceTracing::traceLayers(const char* where) {
-    std::unique_lock<std::mutex> sfLock(mFlinger.mDrawingStateLock);
-    LayersTraceProto entry = traceLayersLocked(where);
-    sfLock.unlock();
-    std::scoped_lock bufferLock(mTraceLock);
+void SurfaceTracing::addFirstEntry() {
+    LayersTraceProto entry;
+    {
+        std::scoped_lock lock(mSfLock);
+        entry = traceLayersLocked("tracing.enable");
+    }
+    addTraceToBuffer(entry);
+}
+
+LayersTraceProto SurfaceTracing::traceWhenNotified() {
+    std::unique_lock<std::mutex> lock(mSfLock);
+    mCanStartTrace.wait(lock);
+    android::base::ScopedLockAssertion assumeLock(mSfLock);
+    LayersTraceProto entry = traceLayersLocked(mWhere);
+    lock.unlock();
+    return entry;
+}
+
+bool SurfaceTracing::addTraceToBuffer(LayersTraceProto& entry) {
+    std::scoped_lock lock(mTraceLock);
     mBuffer.emplace(std::move(entry));
+    if (mWriteToFile) {
+        writeProtoFileLocked();
+        mWriteToFile = false;
+    }
+    return mEnabled;
 }
 
 void SurfaceTracing::notify(const char* where) {
-    std::lock_guard<std::mutex> sfLock(mFlinger.mDrawingStateLock);
+    std::scoped_lock lock(mSfLock);
     mWhere = where;
-    mConditionalVariable.notify_one();
+    mCanStartTrace.notify_one();
 }
 
 void SurfaceTracing::writeToFileAsync() {
-    std::lock_guard<std::mutex> bufferLock(mTraceLock);
+    std::scoped_lock lock(mTraceLock);
     mWriteToFile = true;
-    mConditionalVariable.notify_one();
+    mCanStartTrace.notify_one();
 }
 
 void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
@@ -102,12 +112,11 @@
 }
 
 void SurfaceTracing::enable() {
-    std::lock_guard<std::mutex> bufferLock(mTraceLock);
+    std::scoped_lock lock(mTraceLock);
 
     if (mEnabled) {
         return;
     }
-
     mBuffer.reset(mBufferSize);
     mEnabled = true;
     mThread = std::thread(&SurfaceTracing::mainLoop, this);
@@ -119,7 +128,7 @@
 }
 
 bool SurfaceTracing::disable() {
-    std::lock_guard<std::mutex> bufferLock(mTraceLock);
+    std::scoped_lock lock(mTraceLock);
 
     if (!mEnabled) {
         return false;
@@ -127,28 +136,33 @@
 
     mEnabled = false;
     mWriteToFile = true;
-    mConditionalVariable.notify_all();
+    mCanStartTrace.notify_all();
     return true;
 }
 
 bool SurfaceTracing::isEnabled() const {
-    std::lock_guard<std::mutex> bufferLock(mTraceLock);
+    std::scoped_lock lock(mTraceLock);
     return mEnabled;
 }
 
 void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) {
-    std::lock_guard<std::mutex> bufferLock(mTraceLock);
+    std::scoped_lock lock(mTraceLock);
     mBufferSize = bufferSizeInByte;
     mBuffer.setSize(bufferSizeInByte);
 }
 
+void SurfaceTracing::setTraceFlags(uint32_t flags) {
+    std::scoped_lock lock(mSfLock);
+    mTraceFlags = flags;
+}
+
 LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
     ATRACE_CALL();
 
     LayersTraceProto entry;
     entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
     entry.set_where(where);
-    LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing));
+    LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing, mTraceFlags));
     entry.mutable_layers()->Swap(&layers);
 
     return entry;
@@ -179,8 +193,7 @@
 }
 
 void SurfaceTracing::dump(std::string& result) const {
-    std::lock_guard<std::mutex> bufferLock(mTraceLock);
-
+    std::scoped_lock lock(mTraceLock);
     base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
     base::StringAppendF(&result, "  number of entries: %zu (%.2fMB / %.2fMB)\n",
                         mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 9484480..4be2ee9 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -41,7 +41,7 @@
  */
 class SurfaceTracing {
 public:
-    SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {}
+    SurfaceTracing(SurfaceFlinger& flinger);
     void enable();
     bool disable();
     status_t writeToFile();
@@ -52,6 +52,14 @@
     void writeToFileAsync();
     void dump(std::string& result) const;
 
+    enum : uint32_t {
+        TRACE_CRITICAL = 1 << 0,
+        TRACE_INPUT = 1 << 1,
+        TRACE_EXTRA = 1 << 2,
+        TRACE_ALL = 0xffffffff
+    };
+    void setTraceFlags(uint32_t flags);
+
 private:
     static constexpr auto kDefaultBufferCapInByte = 100_MB;
     static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb";
@@ -74,18 +82,24 @@
     };
 
     void mainLoop();
-    void traceLayers(const char* where);
-    LayersTraceProto traceLayersLocked(const char* where);
+    void addFirstEntry();
+    LayersTraceProto traceWhenNotified();
+    LayersTraceProto traceLayersLocked(const char* where) REQUIRES(mSfLock);
+
+    // Returns true if trace is enabled.
+    bool addTraceToBuffer(LayersTraceProto& entry);
     void writeProtoFileLocked() REQUIRES(mTraceLock);
 
     const SurfaceFlinger& mFlinger;
-
-    const char* mWhere = "";
     status_t mLastErr = NO_ERROR;
     std::thread mThread;
-    std::condition_variable mConditionalVariable;
-    mutable std::mutex mTraceLock;
+    std::condition_variable mCanStartTrace;
 
+    std::mutex& mSfLock;
+    uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_ALL;
+    const char* mWhere GUARDED_BY(mSfLock) = "";
+
+    mutable std::mutex mTraceLock;
     LayersTraceBuffer mBuffer GUARDED_BY(mTraceLock);
     size_t mBufferSize GUARDED_BY(mTraceLock) = kDefaultBufferCapInByte;
     bool mEnabled GUARDED_BY(mTraceLock) = false;
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index d2b7fe0..6e0c1e2 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -100,26 +100,48 @@
     addCallbackHandle(handle);
 }
 
-void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
-    const sp<IBinder> listener = IInterface::asBinder(handle->listener);
+void TransactionCompletedThread::addCallback(
+        const sp<ITransactionCompletedListener>& transactionListener,
+        const std::vector<CallbackId>& callbackIds) {
+    std::lock_guard lock(mMutex);
+    addCallbackLocked(transactionListener, callbackIds);
+}
 
+status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
+    status_t err = addCallbackLocked(handle->listener, handle->callbackIds);
+    if (err != NO_ERROR) {
+        ALOGE("cannot add callback, err: %d", err);
+        return err;
+    }
+
+    const sp<IBinder> listener = IInterface::asBinder(handle->listener);
+    auto& listenerStats = mListenerStats[listener];
+    auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
+
+    transactionStats.latchTime = handle->latchTime;
+    transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
+                                               handle->previousReleaseFence);
+    return NO_ERROR;
+}
+
+status_t TransactionCompletedThread::addCallbackLocked(
+        const sp<ITransactionCompletedListener>& transactionListener,
+        const std::vector<CallbackId>& callbackIds) {
+    const sp<IBinder> listener = IInterface::asBinder(transactionListener);
     // If we don't already have a reference to this listener, linkToDeath so we get a notification
     // if it dies.
     if (mListenerStats.count(listener) == 0) {
-        status_t error = listener->linkToDeath(mDeathRecipient);
-        if (error != NO_ERROR) {
-            ALOGE("cannot add callback handle because linkToDeath failed, err: %d", error);
-            return;
+        status_t err = listener->linkToDeath(mDeathRecipient);
+        if (err != NO_ERROR) {
+            ALOGE("cannot add callback because linkToDeath failed, err: %d", err);
+            return err;
         }
     }
 
     auto& listenerStats = mListenerStats[listener];
-    listenerStats.listener = handle->listener;
-
-    auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
-    transactionStats.latchTime = handle->latchTime;
-    transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
-                                               handle->previousReleaseFence);
+    listenerStats.listener = transactionListener;
+    listenerStats.transactionStats[callbackIds];
+    return NO_ERROR;
 }
 
 void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index f49306d..88808fd 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -64,6 +64,11 @@
     // presented this frame.
     void addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
 
+    // Adds listener and callbackIds in case there are no SurfaceControls that are supposed
+    // to be included in the callback.
+    void addCallback(const sp<ITransactionCompletedListener>& transactionListener,
+                     const std::vector<CallbackId>& callbackIds);
+
     void addPresentFence(const sp<Fence>& presentFence);
 
     void sendCallbacks();
@@ -71,7 +76,9 @@
 private:
     void threadMain();
 
-    void addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
+    status_t addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
+    status_t addCallbackLocked(const sp<ITransactionCompletedListener>& transactionListener,
+                               const std::vector<CallbackId>& callbackIds) REQUIRES(mMutex);
 
     class ThreadDeathRecipient : public IBinder::DeathRecipient {
     public:
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index fd4695e..b097505 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -96,6 +96,8 @@
   FloatRectProto source_bounds = 44;
   FloatRectProto bounds = 45;
   FloatRectProto screen_bounds = 46;
+
+  InputWindowInfoProto input_window_info = 47;
 }
 
 message PositionProto {
@@ -155,3 +157,24 @@
   // frame number the barrier is waiting on.
   uint64 frame_number = 2;
 }
+
+message InputWindowInfoProto {
+    uint32 layout_params_flags = 1;
+    uint32 layout_params_type = 2;
+    RectProto frame = 3;
+    RegionProto touchable_region = 4;
+
+    uint32 surface_inset = 5;
+    bool visible = 6;
+    bool can_receive_keys = 7;
+    bool has_focus = 8;
+    bool has_wallpaper = 9;
+
+    float global_scale_factor = 10;
+    float window_x_scale = 11;
+    float window_y_scale = 12;
+
+    uint32 crop_layer_id = 13;
+    bool replace_touchable_region_with_crop = 14;
+    RectProto touchable_region_crop = 15;
+}
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 25ce4ac..12b41fd 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -47,6 +47,7 @@
         "LayerMetadataTest.cpp",
         "SchedulerTest.cpp",
         "SchedulerUtilsTest.cpp",
+        "RefreshRateConfigsTest.cpp",
         "RefreshRateStatsTest.cpp",
         "TimeStatsTest.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
new file mode 100644
index 0000000..b218ad6
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "SchedulerUnittests"
+
+#include <gmock/gmock.h>
+#include <log/log.h>
+#include <thread>
+
+#include "DisplayHardware/HWC2.h"
+#include "Scheduler/RefreshRateConfigs.h"
+#include "mock/DisplayHardware/MockDisplay.h"
+
+using namespace std::chrono_literals;
+using testing::_;
+
+namespace android {
+namespace scheduler {
+
+using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+using RefreshRate = RefreshRateConfigs::RefreshRate;
+
+class RefreshRateConfigsTest : public testing::Test {
+protected:
+    static constexpr int CONFIG_ID_60 = 0;
+    static constexpr int CONFIG_ID_90 = 1;
+    static constexpr int64_t VSYNC_60 = 16666667;
+    static constexpr int64_t VSYNC_90 = 11111111;
+
+    RefreshRateConfigsTest();
+    ~RefreshRateConfigsTest();
+
+    void assertRatesEqual(const RefreshRate& left, const RefreshRate& right) {
+        ASSERT_EQ(left.configId, right.configId);
+        ASSERT_EQ(left.name, right.name);
+        ASSERT_EQ(left.fps, right.fps);
+    }
+};
+
+RefreshRateConfigsTest::RefreshRateConfigsTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+RefreshRateConfigsTest::~RefreshRateConfigsTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) {
+    std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
+    RefreshRateConfigs configs(displayConfigs);
+
+    // We always store a configuration for screen off.
+    const auto& rates = configs.getRefreshRates();
+    ASSERT_EQ(1, rates.size());
+    const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
+    ASSERT_NE(rates.end(), powerSavingRate);
+    ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE));
+    ASSERT_EQ(rates.end(), rates.find(RefreshRateType::DEFAULT));
+
+    RefreshRate expectedConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
+    assertRatesEqual(expectedConfig, *powerSavingRate->second);
+
+    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    assertRatesEqual(expectedConfig, *configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+    ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::DEFAULT));
+
+    // Sanity check that getRefreshRate() does not modify the underlying configs.
+    ASSERT_EQ(1, configs.getRefreshRates().size());
+}
+
+TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) {
+    auto display = new Hwc2::mock::Display();
+    std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
+    auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
+    config60.setVsyncPeriod(VSYNC_60);
+    displayConfigs.push_back(config60.build());
+    RefreshRateConfigs configs(displayConfigs);
+
+    const auto& rates = configs.getRefreshRates();
+    ASSERT_EQ(2, rates.size());
+    const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
+    const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
+    ASSERT_NE(rates.end(), powerSavingRate);
+    ASSERT_NE(rates.end(), defaultRate);
+    ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE));
+
+    RefreshRate expectedPowerSavingConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
+    assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second);
+    RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60};
+    assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
+
+    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    assertRatesEqual(expectedPowerSavingConfig,
+                     *configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT));
+    assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT));
+    ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+
+    // Sanity check that getRefreshRate() does not modify the underlying configs.
+    ASSERT_EQ(2, configs.getRefreshRates().size());
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) {
+    auto display = new Hwc2::mock::Display();
+    std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
+    auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
+    config60.setVsyncPeriod(VSYNC_60);
+    displayConfigs.push_back(config60.build());
+    auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
+    config90.setVsyncPeriod(VSYNC_90);
+    displayConfigs.push_back(config90.build());
+    RefreshRateConfigs configs(displayConfigs);
+
+    const auto& rates = configs.getRefreshRates();
+    ASSERT_EQ(3, rates.size());
+    const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
+    const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
+    const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE);
+    ASSERT_NE(rates.end(), powerSavingRate);
+    ASSERT_NE(rates.end(), defaultRate);
+    ASSERT_NE(rates.end(), performanceRate);
+
+    RefreshRate expectedPowerSavingConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
+    assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second);
+    RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60};
+    assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
+    RefreshRate expectedPerformanceConfig = RefreshRate{CONFIG_ID_90, "90fps", 90};
+    assertRatesEqual(expectedPerformanceConfig, *performanceRate->second);
+
+    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    assertRatesEqual(expectedPowerSavingConfig,
+                     *configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT));
+    assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT));
+    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+    assertRatesEqual(expectedPerformanceConfig,
+                     *configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+}
+} // namespace
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 4342dc9..10f5af8 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -27,6 +27,7 @@
 
 using namespace std::chrono_literals;
 using testing::_;
+using testing::AtLeast;
 
 namespace android {
 namespace scheduler {
@@ -75,7 +76,7 @@
     init(configs);
 
     // There is one default config, so the refresh rates should have one item.
-    ASSERT_EQ(1, mRefreshRateStats->getTotalTimes().size());
+    EXPECT_EQ(1, mRefreshRateStats->getTotalTimes().size());
 }
 
 TEST_F(RefreshRateStatsTest, oneConfigTest) {
@@ -88,13 +89,14 @@
 
     init(configs);
 
-    EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(4);
-    EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(2);
+    EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
+    EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
 
     std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
-    ASSERT_EQ(2, times.size());
-    ASSERT_EQ(0, times["ScreenOff"]);
-    ASSERT_EQ(0, times["90fps"]);
+    EXPECT_EQ(2, times.size());
+    EXPECT_NE(0u, times.count("ScreenOff"));
+    EXPECT_EQ(1u, times.count("90fps"));
+    EXPECT_EQ(0, times["90fps"]);
     // Setting up tests on mobile harness can be flaky with time passing, so testing for
     // exact time changes can result in flaxy numbers. To avoid that remember old
     // numbers to make sure the correct values are increasing in the next test.
@@ -104,31 +106,32 @@
     // Screen is off by default.
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    ASSERT_LT(screenOff, times["ScreenOff"]);
-    ASSERT_EQ(0, times["90fps"]);
-    screenOff = times["ScreenOff"];
-
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
-    std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
-    ASSERT_EQ(screenOff, times["ScreenOff"]);
-    ASSERT_LT(ninety, times["90fps"]);
-    ninety = times["90fps"];
-
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
-    std::this_thread::sleep_for(std::chrono::milliseconds(2));
-    times = mRefreshRateStats->getTotalTimes();
-    ASSERT_LT(screenOff, times["ScreenOff"]);
-    ASSERT_EQ(ninety, times["90fps"]);
-    screenOff = times["ScreenOff"];
+    EXPECT_LT(screenOff, times["ScreenOff"]);
+    EXPECT_EQ(0, times["90fps"]);
 
     mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+    std::this_thread::sleep_for(std::chrono::milliseconds(2));
+    times = mRefreshRateStats->getTotalTimes();
+    EXPECT_EQ(screenOff, times["ScreenOff"]);
+    EXPECT_LT(ninety, times["90fps"]);
+
+    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+    ninety = mRefreshRateStats->getTotalTimes()["90fps"];
+    std::this_thread::sleep_for(std::chrono::milliseconds(2));
+    times = mRefreshRateStats->getTotalTimes();
+    EXPECT_LT(screenOff, times["ScreenOff"]);
+    EXPECT_EQ(ninety, times["90fps"]);
+
+    mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+    screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
     // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
     // does not update refresh rates that come from the config.
-    ASSERT_LT(screenOff, times["ScreenOff"]);
-    ASSERT_EQ(ninety, times["90fps"]);
+    EXPECT_LT(screenOff, times["ScreenOff"]);
+    EXPECT_EQ(ninety, times["90fps"]);
 }
 
 TEST_F(RefreshRateStatsTest, twoConfigsTest) {
@@ -145,15 +148,17 @@
 
     init(configs);
 
-    EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(6);
-    EXPECT_CALL(*mTimeStats, recordRefreshRate(60, _)).Times(4);
-    EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(4);
+    EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
+    EXPECT_CALL(*mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
+    EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
 
     std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
-    ASSERT_EQ(3, times.size());
-    ASSERT_EQ(0, times["ScreenOff"]);
-    ASSERT_EQ(0, times["60fps"]);
-    ASSERT_EQ(0, times["90fps"]);
+    EXPECT_EQ(3, times.size());
+    EXPECT_NE(0u, times.count("ScreenOff"));
+    EXPECT_EQ(1u, times.count("60fps"));
+    EXPECT_EQ(0, times["60fps"]);
+    EXPECT_EQ(1u, times.count("90fps"));
+    EXPECT_EQ(0, times["90fps"]);
     // Setting up tests on mobile harness can be flaky with time passing, so testing for
     // exact time changes can result in flaxy numbers. To avoid that remember old
     // numbers to make sure the correct values are increasing in the next test.
@@ -164,61 +169,62 @@
     // Screen is off by default.
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    ASSERT_LT(screenOff, times["ScreenOff"]);
-    ASSERT_EQ(sixty, times["60fps"]);
-    ASSERT_EQ(ninety, times["90fps"]);
-    screenOff = times["ScreenOff"];
+    EXPECT_LT(screenOff, times["ScreenOff"]);
+    EXPECT_EQ(sixty, times["60fps"]);
+    EXPECT_EQ(ninety, times["90fps"]);
 
+    mRefreshRateStats->setConfigMode(CONFIG_ID_90);
     mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    ASSERT_EQ(screenOff, times["ScreenOff"]);
-    ASSERT_EQ(sixty, times["60fps"]);
-    ASSERT_LT(ninety, times["90fps"]);
-    ninety = times["90fps"];
+    EXPECT_EQ(screenOff, times["ScreenOff"]);
+    EXPECT_EQ(sixty, times["60fps"]);
+    EXPECT_LT(ninety, times["90fps"]);
 
     // When power mode is normal, time for configs updates.
     mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+    ninety = mRefreshRateStats->getTotalTimes()["90fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    ASSERT_EQ(screenOff, times["ScreenOff"]);
-    ASSERT_EQ(ninety, times["90fps"]);
-    ASSERT_LT(sixty, times["60fps"]);
-    sixty = times["60fps"];
+    EXPECT_EQ(screenOff, times["ScreenOff"]);
+    EXPECT_EQ(ninety, times["90fps"]);
+    EXPECT_LT(sixty, times["60fps"]);
 
     mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+    sixty = mRefreshRateStats->getTotalTimes()["60fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    ASSERT_EQ(screenOff, times["ScreenOff"]);
-    ASSERT_LT(ninety, times["90fps"]);
-    ASSERT_EQ(sixty, times["60fps"]);
-    ninety = times["90fps"];
+    EXPECT_EQ(screenOff, times["ScreenOff"]);
+    EXPECT_LT(ninety, times["90fps"]);
+    EXPECT_EQ(sixty, times["60fps"]);
 
     mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+    ninety = mRefreshRateStats->getTotalTimes()["90fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    ASSERT_EQ(screenOff, times["ScreenOff"]);
-    ASSERT_EQ(ninety, times["90fps"]);
-    ASSERT_LT(sixty, times["60fps"]);
-    sixty = times["60fps"];
+    EXPECT_EQ(screenOff, times["ScreenOff"]);
+    EXPECT_EQ(ninety, times["90fps"]);
+    EXPECT_LT(sixty, times["60fps"]);
 
     // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
     // does not update refresh rates that come from the config.
     mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
     mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+    sixty = mRefreshRateStats->getTotalTimes()["60fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    ASSERT_LT(screenOff, times["ScreenOff"]);
-    ASSERT_EQ(ninety, times["90fps"]);
-    ASSERT_EQ(sixty, times["60fps"]);
-    screenOff = times["ScreenOff"];
+    EXPECT_LT(screenOff, times["ScreenOff"]);
+    EXPECT_EQ(ninety, times["90fps"]);
+    EXPECT_EQ(sixty, times["60fps"]);
 
     mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+    screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    ASSERT_LT(screenOff, times["ScreenOff"]);
-    ASSERT_EQ(ninety, times["90fps"]);
-    ASSERT_EQ(sixty, times["60fps"]);
+    EXPECT_LT(screenOff, times["ScreenOff"]);
+    EXPECT_EQ(ninety, times["90fps"]);
+    EXPECT_EQ(sixty, times["60fps"]);
 }
 } // namespace
 } // namespace scheduler