Merge "Cache shaders for rounded corners and window transition."
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 738c20f..1fbd2b3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1583,6 +1583,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(),
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..92fac66 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -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..20142aa 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);
@@ -1560,10 +1573,27 @@
         }
         if (class_loader_context != nullptr) {
             AddArg(class_loader_context_arg.c_str());
+            if (!class_loader_context_fds.empty()) {
+                AddArg(class_loader_context_fds_arg.c_str());
+            }
         }
 
         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,
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/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 71b710b..36d5a60 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'");
 }
 
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/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/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 247dc8d..bc63d31 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -68,7 +68,8 @@
                                      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) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
 
@@ -86,6 +87,8 @@
         data.writeStrongBinder(applyToken);
         commands.write(data);
         data.writeInt64(desiredPresentTime);
+        data.writeStrongBinder(uncacheBuffer.token);
+        data.writeUint64(uncacheBuffer.cacheId);
         remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
     }
 
@@ -970,8 +973,13 @@
             inputWindowCommands.read(data);
 
             int64_t desiredPresentTime = data.readInt64();
+
+            cached_buffer_t uncachedBuffer;
+            uncachedBuffer.token = data.readStrongBinder();
+            uncachedBuffer.cacheId = data.readUint64();
+
             setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
-                                desiredPresentTime);
+                                desiredPresentTime, uncachedBuffer);
             return NO_ERROR;
         }
         case BOOT_FINISHED: {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 84ba644..f6ca9e8 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -95,7 +95,7 @@
     }
 
     output.writeStrongBinder(cachedBuffer.token);
-    output.writeInt32(cachedBuffer.bufferId);
+    output.writeUint64(cachedBuffer.cacheId);
     output.writeParcelable(metadata);
 
     output.writeFloat(bgColorAlpha);
@@ -173,7 +173,7 @@
     }
 
     cachedBuffer.token = input.readStrongBinder();
-    cachedBuffer.bufferId = input.readInt32();
+    cachedBuffer.cacheId = input.readUint64();
     input.readParcelable(&metadata);
 
     bgColorAlpha = input.readFloat();
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index b0e8275..39cd62f 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) {
@@ -437,6 +460,8 @@
     }
     mListenerCallbacks.clear();
 
+    cacheBuffers();
+
     Vector<ComposerState> composerStates;
     Vector<DisplayState> displayStates;
     uint32_t flags = 0;
@@ -468,7 +493,8 @@
 
     sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
     sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
-                            mDesiredPresentTime);
+                            mDesiredPresentTime,
+                            {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/);
     mInputWindowCommands.clear();
     mStatus = NO_ERROR;
     return NO_ERROR;
@@ -882,20 +908,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..0ef5b39 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -40,6 +40,7 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+struct cached_buffer_t;
 struct ComposerState;
 struct DisplayState;
 struct DisplayInfo;
@@ -131,7 +132,8 @@
                                      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) = 0;
 
     /* signal that we're done booting.
      * Requires ACCESS_SURFACE_FLINGER permission
@@ -194,8 +196,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..77bf8f1 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -41,6 +41,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.
  */
@@ -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;
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..94b669d 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -560,7 +560,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& /*cachedBuffer*/) override {}
 
     void bootFinished() override {}
     bool authenticateSurfaceTexture(
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 165b75a..da959e3 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -422,18 +422,6 @@
         int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26);
 
 /**
- * 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);
-/**
  * Lock a potentially multi-planar AHardwareBuffer for direct CPU access.
  *
  * This function is similar to AHardwareBuffer_lock, but can lock multi-planar
@@ -518,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/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..40df260 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]");
 }
@@ -371,14 +374,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, fds, count);
+    }
+#endif
     size_t sizeNeeded = GraphicBuffer::getFlattenedSize();
     if (size < sizeNeeded) return NO_MEMORY;
 
@@ -405,7 +423,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,17 +432,11 @@
         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");
-        return NO_MEMORY;
-    }
-
+status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& fds,
+                                  size_t& count) {
     int const* buf = static_cast<int const*>(buffer);
 
     // NOTE: it turns out that some media code generates a flattened GraphicBuffer manually!!!!!
@@ -436,10 +448,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, fds, count);
+#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 +475,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 +503,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 +520,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 +530,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 +538,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 +553,87 @@
     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, int*& fds,
+                                               size_t& count) 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);
+
+    // Do not pass fds if it is BufferHubBuffer backed GraphicBuffer. Not modifying fds or count.
+    fds += 0;
+    count -= 0;
+    return NO_ERROR;
+}
+
+status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& size, int const*& fds,
+                                                 size_t& count) {
+    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()));
+
+    // BufferHubBuffer backed GraphicBuffer does not have flattened handle. Not modifying fds or
+    // count.
+    fds += 0;
+    count -= 0;
+    return NO_ERROR;
+}
+
 bool GraphicBuffer::isBufferHubBuffer() const {
     return mBufferHubBuffer != nullptr;
 }
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 1c88777..c137860 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -21,6 +21,8 @@
 #include <sys/types.h>
 
 #include <string>
+#include <utility>
+#include <vector>
 
 #include <android/hardware_buffer.h>
 #include <ui/ANativeObjectBase.h>
@@ -42,6 +44,8 @@
 
 class GraphicBufferMapper;
 
+using GraphicBufferDeathCallback = std::function<void(void* /*context*/, uint64_t bufferId)>;
+
 // ===========================================================================
 // GraphicBuffer
 // ===========================================================================
@@ -219,6 +223,8 @@
         return mBufferMapper.getMapperVersion();
     }
 
+    void addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context);
+
 #ifndef LIBUI_IN_VNDK
     // Returns whether this GraphicBuffer is backed by BufferHubBuffer.
     bool isBufferHubBuffer() const;
@@ -280,7 +286,33 @@
     // 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, int*& fds, size_t& count) 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, int const*& fds,
+                                      size_t& count);
+
     // Stores a BufferHubBuffer that handles buffer signaling, identification.
     std::unique_ptr<BufferHubBuffer> mBufferHubBuffer;
 #endif // LIBUI_IN_VNDK
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/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/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 0cc37a0..a45b8a5 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -4314,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);
     }
 }
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/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 1ca0b02..5efa4e0 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;
 }
 
@@ -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/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 07fe03e..898d37e 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1845,7 +1845,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;
@@ -1853,114 +1854,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 b7cfc16..83ff3b6 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; }
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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 77c8d10..ad4a769 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3508,13 +3508,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, postTime,
+                     privileged] = transactionQueue.front();
             if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
                 break;
             }
             applyTransactionState(states, displays, flags, mPendingInputWindowCommands,
-                                  desiredPresentTime, postTime, privileged);
+                                  desiredPresentTime, uncacheBuffer, postTime, privileged,
+                                  /*isMainThread*/ true);
             transactionQueue.pop();
         }
 
@@ -3571,7 +3573,8 @@
                                          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) {
     ATRACE_CALL();
 
     const int64_t postTime = systemTime();
@@ -3588,20 +3591,22 @@
     if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
         !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
         mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
-                                               postTime, privileged);
+                                               uncacheBuffer, postTime, privileged);
         setTransactionFlags(eTransactionNeeded);
         return;
     }
 
     applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime,
-                          postTime, privileged);
+                          uncacheBuffer, 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 int64_t postTime, bool privileged,
+                                           bool isMainThread) {
     uint32_t transactionFlags = 0;
 
     if (flags & eAnimation) {
@@ -3636,6 +3641,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 +3674,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
@@ -3972,16 +3986,20 @@
             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 +4243,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 +4657,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 +5007,9 @@
         code == IBinder::SYSPROPS_TRANSACTION) {
         return OK;
     }
-    // Numbers from 1000 to 1032 are currently use for backdoors. The code
+    // Numbers from 1000 to 1033 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 <= 1033) {
         ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
         return OK;
     }
@@ -5298,6 +5317,14 @@
                 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;
+            }
         }
     }
     return err;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0d39cb5..26d0cd1 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -431,7 +431,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) override;
     void bootFinished() override;
     bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& bufferProducer) const override;
@@ -577,8 +578,9 @@
     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 int64_t postTime,
+                               bool privileged, bool isMainThread = false) REQUIRES(mStateLock);
     bool flushTransactionQueues();
     uint32_t getTransactionFlags(uint32_t flags);
     uint32_t peekTransactionFlags();
@@ -895,7 +897,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 +1061,13 @@
     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,
+                         int64_t postTime, bool privileged)
               : states(composerStates),
                 displays(displayStates),
                 flags(transactionFlags),
                 desiredPresentTime(desiredPresentTime),
+                buffer(uncacheBuffer),
                 postTime(postTime),
                 privileged(privileged) {}
 
@@ -1070,6 +1075,7 @@
         Vector<DisplayState> displays;
         uint32_t flags;
         const int64_t desiredPresentTime;
+        cached_buffer_t buffer;
         const int64_t postTime;
         bool privileged;
     };
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/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;
+}