Merge "Enable more ColorSpaces in RenderEngine"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 74dbf4b..a2491e5 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -86,9 +86,11 @@
     shared_libs: [
         "android.hardware.dumpstate@1.0",
         "android.hardware.dumpstate@1.1",
+        "android.hardware.dumpstate-V1-ndk",
         "libziparchive",
         "libbase",
         "libbinder",
+        "libbinder_ndk",
         "libcrypto",
         "libcutils",
         "libdebuggerd_client",
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index ba25a5a..77915d5 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -192,7 +192,7 @@
     dprintf(fd, "progress:\n");
     ds_->progress_->Dump(fd, "  ");
     dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
-    dprintf(fd, "bugreport_mode: %s\n", ds_->options_->bugreport_mode.c_str());
+    dprintf(fd, "bugreport_mode: %s\n", ds_->options_->bugreport_mode_string.c_str());
     dprintf(fd, "version: %s\n", ds_->version_.c_str());
     dprintf(fd, "bugreport_dir: %s\n", destination.c_str());
     dprintf(fd, "screenshot_path: %s\n", ds_->screenshot_path_.c_str());
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index eab72f4..32e680d 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -57,12 +57,15 @@
 #include <utility>
 #include <vector>
 
+#include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
 #include <android-base/file.h>
 #include <android-base/properties.h>
 #include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 #include <android/content/pm/IPackageManagerNative.h>
 #include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
 #include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
@@ -89,11 +92,10 @@
 #include "DumpstateService.h"
 #include "dumpstate.h"
 
-using IDumpstateDevice_1_0 = ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
-using IDumpstateDevice_1_1 = ::android::hardware::dumpstate::V1_1::IDumpstateDevice;
-using ::android::hardware::dumpstate::V1_1::DumpstateMode;
-using ::android::hardware::dumpstate::V1_1::DumpstateStatus;
-using ::android::hardware::dumpstate::V1_1::toString;
+namespace dumpstate_hal_hidl_1_0 = android::hardware::dumpstate::V1_0;
+namespace dumpstate_hal_hidl = android::hardware::dumpstate::V1_1;
+namespace dumpstate_hal_aidl = aidl::android::hardware::dumpstate;
+
 using ::std::literals::chrono_literals::operator""ms;
 using ::std::literals::chrono_literals::operator""s;
 using ::std::placeholders::_1;
@@ -807,7 +809,7 @@
     printf("Bugreport format version: %s\n", version_.c_str());
     printf("Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d args=%s bugreport_mode=%s\n",
            id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(),
-           options_->args.c_str(), options_->bugreport_mode.c_str());
+           options_->args.c_str(), options_->bugreport_mode_string.c_str());
     printf("\n");
 }
 
@@ -2199,6 +2201,194 @@
     return RunStatus::OK;
 }
 
+static dumpstate_hal_hidl::DumpstateMode GetDumpstateHalModeHidl(
+    const Dumpstate::BugreportMode bugreport_mode) {
+    switch (bugreport_mode) {
+        case Dumpstate::BugreportMode::BUGREPORT_FULL:
+            return dumpstate_hal_hidl::DumpstateMode::FULL;
+        case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
+            return dumpstate_hal_hidl::DumpstateMode::INTERACTIVE;
+        case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
+            return dumpstate_hal_hidl::DumpstateMode::REMOTE;
+        case Dumpstate::BugreportMode::BUGREPORT_WEAR:
+            return dumpstate_hal_hidl::DumpstateMode::WEAR;
+        case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
+            return dumpstate_hal_hidl::DumpstateMode::CONNECTIVITY;
+        case Dumpstate::BugreportMode::BUGREPORT_WIFI:
+            return dumpstate_hal_hidl::DumpstateMode::WIFI;
+        case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
+            return dumpstate_hal_hidl::DumpstateMode::DEFAULT;
+    }
+    return dumpstate_hal_hidl::DumpstateMode::DEFAULT;
+}
+
+static dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode GetDumpstateHalModeAidl(
+    const Dumpstate::BugreportMode bugreport_mode) {
+    switch (bugreport_mode) {
+        case Dumpstate::BugreportMode::BUGREPORT_FULL:
+            return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::FULL;
+        case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
+            return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::INTERACTIVE;
+        case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
+            return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::REMOTE;
+        case Dumpstate::BugreportMode::BUGREPORT_WEAR:
+            return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::WEAR;
+        case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
+            return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::CONNECTIVITY;
+        case Dumpstate::BugreportMode::BUGREPORT_WIFI:
+            return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::WIFI;
+        case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
+            return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::DEFAULT;
+    }
+    return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::DEFAULT;
+}
+
+static void DoDumpstateBoardHidl(
+    const sp<dumpstate_hal_hidl_1_0::IDumpstateDevice> dumpstate_hal_1_0,
+    const std::vector<::ndk::ScopedFileDescriptor>& dumpstate_fds,
+    const Dumpstate::BugreportMode bugreport_mode,
+    const size_t timeout_sec) {
+
+    using ScopedNativeHandle =
+        std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
+    ScopedNativeHandle handle(native_handle_create(static_cast<int>(dumpstate_fds.size()), 0),
+                              [](native_handle_t* handle) {
+                                  // we don't close file handle's here
+                                  // via native_handle_close(handle)
+                                  // instead we let dumpstate_fds close the file handles when
+                                  // dumpstate_fds gets destroyed
+                                  native_handle_delete(handle);
+                              });
+    if (handle == nullptr) {
+        MYLOGE("Could not create native_handle for dumpstate HAL\n");
+        return;
+    }
+
+    for (size_t i = 0; i < dumpstate_fds.size(); i++) {
+        handle.get()->data[i] = dumpstate_fds[i].get();
+    }
+
+    // Prefer version 1.1 if available. New devices launching with R are no longer allowed to
+    // implement just 1.0.
+    const char* descriptor_to_kill;
+    using DumpstateBoardTask = std::packaged_task<bool()>;
+    DumpstateBoardTask dumpstate_board_task;
+    sp<dumpstate_hal_hidl::IDumpstateDevice> dumpstate_hal(
+        dumpstate_hal_hidl::IDumpstateDevice::castFrom(dumpstate_hal_1_0));
+    if (dumpstate_hal != nullptr) {
+        MYLOGI("Using IDumpstateDevice v1.1 HIDL HAL");
+
+        dumpstate_hal_hidl::DumpstateMode dumpstate_hal_mode =
+            GetDumpstateHalModeHidl(bugreport_mode);
+
+        descriptor_to_kill = dumpstate_hal_hidl::IDumpstateDevice::descriptor;
+        dumpstate_board_task =
+            DumpstateBoardTask([timeout_sec, dumpstate_hal_mode, dumpstate_hal, &handle]() -> bool {
+                ::android::hardware::Return<dumpstate_hal_hidl::DumpstateStatus> status =
+                    dumpstate_hal->dumpstateBoard_1_1(handle.get(), dumpstate_hal_mode,
+                                                      SEC_TO_MSEC(timeout_sec));
+                if (!status.isOk()) {
+                    MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+                    return false;
+                } else if (status != dumpstate_hal_hidl::DumpstateStatus::OK) {
+                    MYLOGE("dumpstateBoard failed with DumpstateStatus::%s\n",
+                           dumpstate_hal_hidl::toString(status).c_str());
+                    return false;
+                }
+                return true;
+            });
+    } else {
+        MYLOGI("Using IDumpstateDevice v1.0 HIDL HAL");
+
+        descriptor_to_kill = dumpstate_hal_hidl_1_0::IDumpstateDevice::descriptor;
+        dumpstate_board_task = DumpstateBoardTask([dumpstate_hal_1_0, &handle]() -> bool {
+            ::android::hardware::Return<void> status =
+                dumpstate_hal_1_0->dumpstateBoard(handle.get());
+            if (!status.isOk()) {
+                MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+                return false;
+            }
+            return true;
+        });
+    }
+    auto result = dumpstate_board_task.get_future();
+    std::thread(std::move(dumpstate_board_task)).detach();
+
+    if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
+        MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate HAL\n", timeout_sec);
+        if (!android::base::SetProperty(
+                "ctl.interface_restart",
+                android::base::StringPrintf("%s/default", descriptor_to_kill))) {
+            MYLOGE("Couldn't restart dumpstate HAL\n");
+        }
+    }
+    // Wait some time for init to kill dumpstate vendor HAL
+    constexpr size_t killing_timeout_sec = 10;
+    if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
+        MYLOGE(
+            "killing dumpstateBoard timed out after %zus, continue and "
+            "there might be racing in content\n",
+            killing_timeout_sec);
+    }
+}
+
+static void DoDumpstateBoardAidl(
+    const std::shared_ptr<dumpstate_hal_aidl::IDumpstateDevice> dumpstate_hal,
+    const std::vector<::ndk::ScopedFileDescriptor>& dumpstate_fds,
+    const Dumpstate::BugreportMode bugreport_mode, const size_t timeout_sec) {
+    MYLOGI("Using IDumpstateDevice AIDL HAL");
+
+    const char* descriptor_to_kill;
+    using DumpstateBoardTask = std::packaged_task<bool()>;
+    DumpstateBoardTask dumpstate_board_task;
+    dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode dumpstate_hal_mode =
+        GetDumpstateHalModeAidl(bugreport_mode);
+
+    descriptor_to_kill = dumpstate_hal_aidl::IDumpstateDevice::descriptor;
+    dumpstate_board_task = DumpstateBoardTask([dumpstate_hal, &dumpstate_fds, dumpstate_hal_mode,
+                                               timeout_sec]() -> bool {
+        auto status = dumpstate_hal->dumpstateBoard(dumpstate_fds, dumpstate_hal_mode, timeout_sec);
+
+        if (!status.isOk()) {
+            MYLOGE("dumpstateBoard failed: %s\n", status.getDescription().c_str());
+            return false;
+        }
+        return true;
+    });
+    auto result = dumpstate_board_task.get_future();
+    std::thread(std::move(dumpstate_board_task)).detach();
+
+    if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
+        MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate HAL\n", timeout_sec);
+        if (!android::base::SetProperty(
+                "ctl.interface_restart",
+                android::base::StringPrintf("%s/default", descriptor_to_kill))) {
+            MYLOGE("Couldn't restart dumpstate HAL\n");
+        }
+    }
+    // Wait some time for init to kill dumpstate vendor HAL
+    constexpr size_t killing_timeout_sec = 10;
+    if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
+        MYLOGE(
+            "killing dumpstateBoard timed out after %zus, continue and "
+            "there might be racing in content\n",
+            killing_timeout_sec);
+    }
+}
+
+static std::shared_ptr<dumpstate_hal_aidl::IDumpstateDevice> GetDumpstateBoardAidlService() {
+    const std::string aidl_instance_name =
+        std::string(dumpstate_hal_aidl::IDumpstateDevice::descriptor) + "/default";
+
+    if (!AServiceManager_isDeclared(aidl_instance_name.c_str())) {
+        return nullptr;
+    }
+
+    ndk::SpAIBinder dumpstateBinder(AServiceManager_waitForService(aidl_instance_name.c_str()));
+
+    return dumpstate_hal_aidl::IDumpstateDevice::fromBinder(dumpstateBinder);
+}
+
 void Dumpstate::DumpstateBoard(int out_fd) {
     dprintf(out_fd, "========================================================\n");
     dprintf(out_fd, "== Board\n");
@@ -2220,8 +2410,7 @@
     if (mount_debugfs) {
         RunCommand("mount debugfs", {"mount", "-t", "debugfs", "debugfs", "/sys/kernel/debug"},
                    AS_ROOT_20);
-        RunCommand("chmod debugfs", {"chmod", "0755", "/sys/kernel/debug"},
-                   AS_ROOT_20);
+        RunCommand("chmod debugfs", {"chmod", "0755", "/sys/kernel/debug"}, AS_ROOT_20);
     }
 
     std::vector<std::string> paths;
@@ -2233,23 +2422,31 @@
             std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
     }
 
-    sp<IDumpstateDevice_1_0> dumpstate_device_1_0(IDumpstateDevice_1_0::getService());
-    if (dumpstate_device_1_0 == nullptr) {
-        MYLOGE("No IDumpstateDevice implementation\n");
+    // get dumpstate HAL AIDL implementation
+    std::shared_ptr<dumpstate_hal_aidl::IDumpstateDevice> dumpstate_hal_handle_aidl(
+        GetDumpstateBoardAidlService());
+    if (dumpstate_hal_handle_aidl == nullptr) {
+        MYLOGI("No IDumpstateDevice AIDL implementation\n");
+    }
+
+    // get dumpstate HAL HIDL implementation, only if AIDL HAL implementation not found
+    sp<dumpstate_hal_hidl_1_0::IDumpstateDevice> dumpstate_hal_handle_hidl_1_0 = nullptr;
+    if (dumpstate_hal_handle_aidl == nullptr) {
+        dumpstate_hal_handle_hidl_1_0 = dumpstate_hal_hidl_1_0::IDumpstateDevice::getService();
+        if (dumpstate_hal_handle_hidl_1_0 == nullptr) {
+            MYLOGI("No IDumpstateDevice HIDL implementation\n");
+        }
+    }
+
+    // if neither HIDL nor AIDL implementation found, then return
+    if (dumpstate_hal_handle_hidl_1_0 == nullptr && dumpstate_hal_handle_aidl == nullptr) {
+        MYLOGE("Could not find IDumpstateDevice implementation\n");
         return;
     }
 
-    using ScopedNativeHandle =
-            std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
-    ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
-                              [](native_handle_t* handle) {
-                                  native_handle_close(handle);
-                                  native_handle_delete(handle);
-                              });
-    if (handle == nullptr) {
-        MYLOGE("Could not create native_handle\n");
-        return;
-    }
+    // this is used to hold the file descriptors and when this variable goes out of scope
+    // the file descriptors are closed
+    std::vector<::ndk::ScopedFileDescriptor> dumpstate_fds;
 
     // TODO(128270426): Check for consent in between?
     for (size_t i = 0; i < paths.size(); i++) {
@@ -2262,65 +2459,26 @@
             MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
             return;
         }
-        handle.get()->data[i] = fd.release();
+
+        dumpstate_fds.emplace_back(fd.release());
+        // we call fd.release() here to make sure "fd" does not get closed
+        // after "fd" goes out of scope after this block.
+        // "fd" will be closed when "dumpstate_fds" goes out of scope
+        // i.e. when we exit this function
     }
 
     // Given that bugreport is required to diagnose failures, it's better to set an arbitrary amount
     // of timeout for IDumpstateDevice than to block the rest of bugreport. In the timeout case, we
     // will kill the HAL and grab whatever it dumped in time.
     constexpr size_t timeout_sec = 30;
-    // Prefer version 1.1 if available. New devices launching with R are no longer allowed to
-    // implement just 1.0.
-    const char* descriptor_to_kill;
-    using DumpstateBoardTask = std::packaged_task<bool()>;
-    DumpstateBoardTask dumpstate_board_task;
-    sp<IDumpstateDevice_1_1> dumpstate_device_1_1(
-        IDumpstateDevice_1_1::castFrom(dumpstate_device_1_0));
-    if (dumpstate_device_1_1 != nullptr) {
-        MYLOGI("Using IDumpstateDevice v1.1");
-        descriptor_to_kill = IDumpstateDevice_1_1::descriptor;
-        dumpstate_board_task = DumpstateBoardTask([this, dumpstate_device_1_1, &handle]() -> bool {
-            ::android::hardware::Return<DumpstateStatus> status =
-                dumpstate_device_1_1->dumpstateBoard_1_1(handle.get(), options_->dumpstate_hal_mode,
-                                                         SEC_TO_MSEC(timeout_sec));
-            if (!status.isOk()) {
-                MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
-                return false;
-            } else if (status != DumpstateStatus::OK) {
-                MYLOGE("dumpstateBoard failed with DumpstateStatus::%s\n", toString(status).c_str());
-                return false;
-            }
-            return true;
-        });
-    } else {
-        MYLOGI("Using IDumpstateDevice v1.0");
-        descriptor_to_kill = IDumpstateDevice_1_0::descriptor;
-        dumpstate_board_task = DumpstateBoardTask([dumpstate_device_1_0, &handle]() -> bool {
-            ::android::hardware::Return<void> status =
-                dumpstate_device_1_0->dumpstateBoard(handle.get());
-            if (!status.isOk()) {
-                MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
-                return false;
-            }
-            return true;
-        });
-    }
-    auto result = dumpstate_board_task.get_future();
-    std::thread(std::move(dumpstate_board_task)).detach();
 
-    if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
-        MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
-        if (!android::base::SetProperty(
-                "ctl.interface_restart",
-                android::base::StringPrintf("%s/default", descriptor_to_kill))) {
-            MYLOGE("Couldn't restart dumpstate HAL\n");
-        }
-    }
-    // Wait some time for init to kill dumpstate vendor HAL
-    constexpr size_t killing_timeout_sec = 10;
-    if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
-        MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
-               "there might be racing in content\n", killing_timeout_sec);
+    if (dumpstate_hal_handle_aidl != nullptr) {
+        DoDumpstateBoardAidl(dumpstate_hal_handle_aidl, dumpstate_fds, options_->bugreport_mode,
+                             timeout_sec);
+    } else if (dumpstate_hal_handle_hidl_1_0 != nullptr) {
+        // run HIDL HAL only if AIDL HAL not found
+        DoDumpstateBoardHidl(dumpstate_hal_handle_hidl_1_0, dumpstate_fds, options_->bugreport_mode,
+                             timeout_sec);
     }
 
     if (mount_debugfs) {
@@ -2333,9 +2491,8 @@
     auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
     for (size_t i = 0; i < paths.size(); i++) {
         struct stat s;
-        if (fstat(handle.get()->data[i], &s) == -1) {
-            MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
-                   strerror(errno));
+        if (fstat(dumpstate_fds[i].get(), &s) == -1) {
+            MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(), strerror(errno));
             file_sizes[i] = -1;
             continue;
         }
@@ -2574,40 +2731,35 @@
                                bool is_screenshot_requested) {
     // Modify com.android.shell.BugreportProgressService#isDefaultScreenshotRequired as well for
     // default system screenshots.
-    options->bugreport_mode = ModeToString(mode);
+    options->bugreport_mode = mode;
+    options->bugreport_mode_string = ModeToString(mode);
     switch (mode) {
         case Dumpstate::BugreportMode::BUGREPORT_FULL:
             options->do_screenshot = is_screenshot_requested;
-            options->dumpstate_hal_mode = DumpstateMode::FULL;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
             // Currently, the dumpstate binder is only used by Shell to update progress.
             options->do_progress_updates = true;
             options->do_screenshot = is_screenshot_requested;
-            options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
             options->do_vibrate = false;
             options->is_remote_mode = true;
             options->do_screenshot = false;
-            options->dumpstate_hal_mode = DumpstateMode::REMOTE;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_WEAR:
             options->do_progress_updates = true;
             options->do_screenshot = is_screenshot_requested;
-            options->dumpstate_hal_mode = DumpstateMode::WEAR;
             break;
         // TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY.
         case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
             options->telephony_only = true;
             options->do_progress_updates = true;
             options->do_screenshot = false;
-            options->dumpstate_hal_mode = DumpstateMode::CONNECTIVITY;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_WIFI:
             options->wifi_only = true;
             options->do_screenshot = false;
-            options->dumpstate_hal_mode = DumpstateMode::WIFI;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
             break;
@@ -2618,13 +2770,14 @@
     MYLOGI(
         "do_vibrate: %d stream_to_socket: %d progress_updates_to_socket: %d do_screenshot: %d "
         "is_remote_mode: %d show_header_only: %d telephony_only: %d "
-        "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s "
+        "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s "
         "limited_only: %d args: %s\n",
         options.do_vibrate, options.stream_to_socket, options.progress_updates_to_socket,
         options.do_screenshot, options.is_remote_mode, options.show_header_only,
         options.telephony_only, options.wifi_only,
-        options.do_progress_updates, options.bugreport_fd.get(), options.bugreport_mode.c_str(),
-        toString(options.dumpstate_hal_mode).c_str(), options.limited_only, options.args.c_str());
+        options.do_progress_updates, options.bugreport_fd.get(),
+        options.bugreport_mode_string.c_str(),
+        options.limited_only, options.args.c_str());
 }
 
 void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
@@ -2838,7 +2991,7 @@
     }
 
     MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s bugreport format version: %s\n",
-           id_, options_->args.c_str(), options_->bugreport_mode.c_str(), version_.c_str());
+           id_, options_->args.c_str(), options_->bugreport_mode_string.c_str(), version_.c_str());
 
     do_early_screenshot_ = options_->do_progress_updates;
 
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 3722383..773e292 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -25,6 +25,7 @@
 #include <string>
 #include <vector>
 
+#include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
 #include <android-base/macros.h>
 #include <android-base/unique_fd.h>
 #include <android/hardware/dumpstate/1.1/types.h>
@@ -400,19 +401,18 @@
         bool limited_only = false;
         // Whether progress updates should be published.
         bool do_progress_updates = false;
-        // The mode we'll use when calling IDumpstateDevice::dumpstateBoard.
+        // this is used to derive dumpstate HAL bug report mode
         // TODO(b/148168577) get rid of the AIDL values, replace them with the HAL values instead.
         // The HAL is actually an API surface that can be validated, while the AIDL is not (@hide).
-        ::android::hardware::dumpstate::V1_1::DumpstateMode dumpstate_hal_mode =
-            ::android::hardware::dumpstate::V1_1::DumpstateMode::DEFAULT;
+        BugreportMode bugreport_mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
         // File descriptor to output zip file. Takes precedence over out_dir.
         android::base::unique_fd bugreport_fd;
         // File descriptor to screenshot file.
         android::base::unique_fd screenshot_fd;
         // Custom output directory.
         std::string out_dir;
-        // Bugreport mode of the bugreport.
-        std::string bugreport_mode;
+        // Bugreport mode of the bugreport as a string
+        std::string bugreport_mode_string;
         // Command-line arguments as string
         std::string args;
         // Notification title and description
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index db508b5..42beb2b 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -33,6 +33,7 @@
 #include <unistd.h>
 #include <thread>
 
+#include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
 #include <android-base/file.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
@@ -47,6 +48,7 @@
 namespace os {
 namespace dumpstate {
 
+using DumpstateDeviceAidl = ::aidl::android::hardware::dumpstate::IDumpstateDevice;
 using ::android::hardware::dumpstate::V1_1::DumpstateMode;
 using ::testing::EndsWith;
 using ::testing::Eq;
@@ -186,7 +188,6 @@
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
     EXPECT_FALSE(options_.limited_only);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
 
 TEST_F(DumpOptionsTest, InitializeAdbBugreport) {
@@ -210,7 +211,6 @@
     EXPECT_FALSE(options_.is_remote_mode);
     EXPECT_FALSE(options_.stream_to_socket);
     EXPECT_FALSE(options_.limited_only);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
 
 TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) {
@@ -234,13 +234,11 @@
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
     EXPECT_FALSE(options_.limited_only);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
 
 TEST_F(DumpOptionsTest, InitializeFullBugReport) {
     options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd, true);
     EXPECT_TRUE(options_.do_screenshot);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::FULL);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -256,7 +254,6 @@
     options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd, true);
     EXPECT_TRUE(options_.do_progress_updates);
     EXPECT_TRUE(options_.do_screenshot);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -272,7 +269,6 @@
     EXPECT_TRUE(options_.is_remote_mode);
     EXPECT_FALSE(options_.do_vibrate);
     EXPECT_FALSE(options_.do_screenshot);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::REMOTE);
 
     // Other options retain default values
     EXPECT_FALSE(options_.progress_updates_to_socket);
@@ -286,7 +282,7 @@
     options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd, true);
     EXPECT_TRUE(options_.do_screenshot);
     EXPECT_TRUE(options_.do_progress_updates);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WEAR);
+
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -302,7 +298,6 @@
     EXPECT_FALSE(options_.do_screenshot);
     EXPECT_TRUE(options_.telephony_only);
     EXPECT_TRUE(options_.do_progress_updates);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::CONNECTIVITY);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -317,7 +312,6 @@
     options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd, false);
     EXPECT_FALSE(options_.do_screenshot);
     EXPECT_TRUE(options_.wifi_only);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WIFI);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -354,7 +348,6 @@
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
     EXPECT_FALSE(options_.stream_to_socket);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
 
 TEST_F(DumpOptionsTest, InitializeDefaultBugReport) {
@@ -371,7 +364,6 @@
 
     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
     EXPECT_TRUE(options_.do_screenshot);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -408,7 +400,6 @@
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
     EXPECT_FALSE(options_.limited_only);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
 
 TEST_F(DumpOptionsTest, InitializePartial2) {
@@ -436,7 +427,6 @@
     EXPECT_FALSE(options_.stream_to_socket);
     EXPECT_FALSE(options_.progress_updates_to_socket);
     EXPECT_FALSE(options_.limited_only);
-    EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
 
 TEST_F(DumpOptionsTest, InitializeHelp) {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index f05426f..dd50ca7 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -649,6 +649,9 @@
 
     // add to shadow queue
     mNumFrameAvailable++;
+    if (mWaitForTransactionCallback && mNumFrameAvailable == 2) {
+        acquireAndReleaseBuffer();
+    }
     ATRACE_INT(mQueuedBufferTrace.c_str(),
                mNumFrameAvailable + mNumAcquired - mPendingRelease.size());
 
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index ec0573a..cd1c810 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -550,7 +550,9 @@
 }
 
 bool InputWindowCommands::empty() const {
-    return focusRequests.empty() && !syncInputWindows;
+    bool empty = true;
+    empty = focusRequests.empty() && !syncInputWindows;
+    return empty;
 }
 
 void InputWindowCommands::clear() {
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index d9beb23..f960e07 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -936,6 +936,20 @@
     EXPECT_EQ(surface->consumeEvent(100), nullptr);
 }
 
+TEST_F(InputSurfacesTest, ignore_touch_region_with_zero_sized_blast) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+
+    std::unique_ptr<BlastInputSurface> bufferSurface =
+            BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0);
+
+    surface->showAt(100, 100);
+    bufferSurface->mInputInfo.touchableRegion.orSelf(Rect(0, 0, 200, 200));
+    bufferSurface->showAt(100, 100, Rect::EMPTY_RECT);
+
+    injectTap(101, 101);
+    surface->expectTap(1, 1);
+}
+
 TEST_F(InputSurfacesTest, drop_input_policy) {
     std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
     surface->doTransaction(
diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
index e88fdd5..d1925cb 100644
--- a/libs/ui/PixelFormat.cpp
+++ b/libs/ui/PixelFormat.cpp
@@ -39,25 +39,6 @@
     return 0;
 }
 
-uint32_t bitsPerPixel(PixelFormat format) {
-    switch (format) {
-        case PIXEL_FORMAT_RGBA_FP16:
-            return 64;
-        case PIXEL_FORMAT_RGBA_8888:
-        case PIXEL_FORMAT_RGBX_8888:
-        case PIXEL_FORMAT_BGRA_8888:
-        case PIXEL_FORMAT_RGBA_1010102:
-            return 32;
-        case PIXEL_FORMAT_RGB_888:
-            return 24;
-        case PIXEL_FORMAT_RGB_565:
-        case PIXEL_FORMAT_RGBA_5551:
-        case PIXEL_FORMAT_RGBA_4444:
-            return 16;
-    }
-    return 0;
-}
-
 // ----------------------------------------------------------------------------
 }; // namespace android
 // ----------------------------------------------------------------------------
diff --git a/libs/ui/include/ui/PixelFormat.h b/libs/ui/include/ui/PixelFormat.h
index 02773d9..91ff39e 100644
--- a/libs/ui/include/ui/PixelFormat.h
+++ b/libs/ui/include/ui/PixelFormat.h
@@ -67,7 +67,6 @@
 typedef int32_t PixelFormat;
 
 uint32_t bytesPerPixel(PixelFormat format);
-uint32_t bitsPerPixel(PixelFormat format);
 
 }; // namespace android
 
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index f16cd63..5560ed7 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -205,6 +205,7 @@
         "SurfaceFlingerDefaultFactory.cpp",
         "SurfaceInterceptor.cpp",
         "Tracing/LayerTracing.cpp",
+        "Tracing/TransactionTracing.cpp",
         "Tracing/TransactionProtoParser.cpp",
         "TransactionCallbackInvoker.cpp",
         "TunnelModeEnabledReporter.cpp",
diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp
index de8e6b3..3663cdb 100644
--- a/services/surfaceflinger/BackgroundExecutor.cpp
+++ b/services/surfaceflinger/BackgroundExecutor.cpp
@@ -32,9 +32,7 @@
             std::vector<std::function<void()>> tasks;
             {
                 std::unique_lock lock(mMutex);
-                android::base::ScopedLockAssertion assumeLock(mMutex);
-                mWorkAvailableCv.wait(lock,
-                                      [&]() REQUIRES(mMutex) { return mDone || !mTasks.empty(); });
+                mWorkAvailableCv.wait(lock, [&]() { return mDone || !mTasks.empty(); });
                 tasks = std::move(mTasks);
                 mTasks.clear();
                 done = mDone;
@@ -49,7 +47,7 @@
 
 BackgroundExecutor::~BackgroundExecutor() {
     {
-        std::scoped_lock lock(mMutex);
+        std::unique_lock lock(mMutex);
         mDone = true;
         mWorkAvailableCv.notify_all();
     }
@@ -59,7 +57,7 @@
 }
 
 void BackgroundExecutor::execute(std::function<void()> task) {
-    std::scoped_lock lock(mMutex);
+    std::unique_lock lock(mMutex);
     mTasks.emplace_back(std::move(task));
     mWorkAvailableCv.notify_all();
 }
diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h
index 6db7dda..6f6d305 100644
--- a/services/surfaceflinger/BackgroundExecutor.h
+++ b/services/surfaceflinger/BackgroundExecutor.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include <android-base/thread_annotations.h>
 #include <utils/Singleton.h>
 #include <condition_variable>
 #include <mutex>
@@ -34,10 +33,10 @@
 
 private:
     std::mutex mMutex;
-    std::condition_variable mWorkAvailableCv GUARDED_BY(mMutex);
-    bool mDone GUARDED_BY(mMutex) = false;
-    std::vector<std::function<void()>> mTasks GUARDED_BY(mMutex);
+    std::condition_variable mWorkAvailableCv;
     std::thread mThread;
+    bool mDone = false;
+    std::vector<std::function<void()>> mTasks;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 490775f..494b61c 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -796,7 +796,7 @@
     wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop;
     WindowInfo tmpInputInfo = mDrawingState.inputInfo;
 
-    mDrawingState = clonedFrom->mDrawingState;
+    cloneDrawingState(clonedFrom.get());
 
     mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop;
     mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 7d40fc8..2fac880 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -61,7 +61,7 @@
     // one of the layers, in this case the original layer, needs to handle the deletion. The
     // original layer and the clone should be removed at the same time so there shouldn't be any
     // issue with the clone layer trying to use the texture.
-    if (mBufferInfo.mBuffer != nullptr && !isClone()) {
+    if (mBufferInfo.mBuffer != nullptr) {
         callReleaseBufferCallback(mDrawingState.releaseBufferListener,
                                   mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber,
                                   mBufferInfo.mFence,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 495d585..dfb99cc 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2169,6 +2169,8 @@
         info.frameRight = 0;
         info.frameBottom = 0;
         info.transform.reset();
+        info.touchableRegion = Region();
+        info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE;
         return;
     }
 
@@ -2416,8 +2418,7 @@
 }
 
 void Layer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
-    // copy drawing state from cloned layer
-    mDrawingState = clonedFrom->mDrawingState;
+    cloneDrawingState(clonedFrom.get());
     mClonedFrom = clonedFrom;
 }
 
@@ -2452,7 +2453,7 @@
     // since we may be able to pull out other children that are still alive.
     if (isClonedFromAlive()) {
         sp<Layer> clonedFrom = getClonedFrom();
-        mDrawingState = clonedFrom->mDrawingState;
+        cloneDrawingState(clonedFrom.get());
         clonedLayersMap.emplace(clonedFrom, this);
     }
 
@@ -2615,6 +2616,13 @@
     return true;
 }
 
+void Layer::cloneDrawingState(const Layer* from) {
+    mDrawingState = from->mDrawingState;
+    // Skip callback info since they are not applicable for cloned layers.
+    mDrawingState.releaseBufferListener = nullptr;
+    mDrawingState.callbackHandles = {};
+}
+
 // ---------------------------------------------------------------------------
 
 std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 47885a4..3f4d48b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -922,6 +922,7 @@
     bool isClone() { return mClonedFrom != nullptr; }
     bool isClonedFromAlive() { return getClonedFrom() != nullptr; }
 
+    void cloneDrawingState(const Layer* from);
     void updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
     void updateClonedChildren(const sp<Layer>& mirrorRoot,
                               std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index daf5980..21f3872 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -93,7 +93,6 @@
 #include <type_traits>
 #include <unordered_map>
 
-#include "BackgroundExecutor.h"
 #include "BufferLayer.h"
 #include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
@@ -359,10 +358,11 @@
 
 SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
       : mFactory(factory),
+        mPid(getpid()),
         mInterceptor(mFactory.createSurfaceInterceptor()),
         mTimeStats(std::make_shared<impl::TimeStats>()),
         mFrameTracer(mFactory.createFrameTracer()),
-        mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())),
+        mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)),
         mCompositionEngine(mFactory.createCompositionEngine()),
         mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
         mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
@@ -491,6 +491,11 @@
     enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false));
 
     enableLatchUnsignaledConfig = getLatchUnsignaledConfig();
+
+    mTransactionTracingEnabled = property_get_bool("debug.sf.enable_transaction_tracing", false);
+    if (mTransactionTracingEnabled) {
+        mTransactionTracing.enable();
+    }
 }
 
 LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
@@ -510,7 +515,7 @@
     mBootFinished = false;
 
     // Sever the link to inputflinger since it's gone as well.
-    BackgroundExecutor::getInstance().execute([=] { mInputFlinger = nullptr; });
+    static_cast<void>(mScheduler->schedule([=] { mInputFlinger = nullptr; }));
 
     // restore initial conditions (default device unblank, etc)
     initializeDisplays();
@@ -721,15 +726,13 @@
 
     sp<IBinder> input(defaultServiceManager()->getService(String16("inputflinger")));
 
-    BackgroundExecutor::getInstance().execute([=] {
+    static_cast<void>(mScheduler->schedule([=] {
         if (input == nullptr) {
             ALOGE("Failed to link to input service");
         } else {
             mInputFlinger = interface_cast<os::IInputFlinger>(input);
         }
-    });
 
-    static_cast<void>(mScheduler->schedule([=] {
         readPersistentProperties();
         mPowerAdvisor.onBootFinished();
         mBootStage = BootStage::FINISHED;
@@ -1989,7 +1992,7 @@
     }
 
     if (mTracingEnabledChanged) {
-        mTracingEnabled = mLayerTracing.isEnabled();
+        mLayerTracingEnabled = mLayerTracing.isEnabled();
         mTracingEnabledChanged = false;
     }
 
@@ -2007,7 +2010,7 @@
 
         bool needsTraversal = false;
         if (clearTransactionFlags(eTransactionFlushNeeded)) {
-            needsTraversal = flushTransactionQueues();
+            needsTraversal = flushTransactionQueues(vsyncId);
         }
 
         const bool shouldCommit =
@@ -2138,7 +2141,7 @@
     modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
 
     mLayersWithQueuedFrames.clear();
-    if (mTracingEnabled) {
+    if (mLayerTracingEnabled) {
         // This will block and should only be used for debugging.
         if (mVisibleRegionsDirty) {
             mLayerTracing.notify("visibleRegionsDirty");
@@ -3047,48 +3050,32 @@
 
 void SurfaceFlinger::updateInputFlinger() {
     ATRACE_CALL();
-    std::vector<WindowInfo> windowInfos;
-    std::vector<DisplayInfo> displayInfos;
-    bool updateWindowInfo = false;
-    if (mVisibleRegionsDirty || mInputInfoChanged) {
-        mInputInfoChanged = false;
-        updateWindowInfo = true;
-        buildWindowInfos(windowInfos, displayInfos);
-    }
-    if (!updateWindowInfo && mInputWindowCommands.empty()) {
+    if (!mInputFlinger) {
         return;
     }
-    BackgroundExecutor::getInstance().execute([updateWindowInfo,
-                                               windowInfos = std::move(windowInfos),
-                                               displayInfos = std::move(displayInfos),
-                                               inputWindowCommands =
-                                                       std::move(mInputWindowCommands),
-                                               this]() {
-        ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
-        if (!mInputFlinger) {
-            return;
-        }
-        if (updateWindowInfo) {
-            mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
-                                                            inputWindowCommands.syncInputWindows);
-        } else if (inputWindowCommands.syncInputWindows) {
-            // If the caller requested to sync input windows, but there are no
-            // changes to input windows, notify immediately.
-            windowInfosReported();
-        }
-        for (const auto& focusRequest : inputWindowCommands.focusRequests) {
-            mInputFlinger->setFocusedWindow(focusRequest);
-        }
-    });
 
+    if (mVisibleRegionsDirty || mInputInfoChanged) {
+        mInputInfoChanged = false;
+        notifyWindowInfos();
+    } else if (mInputWindowCommands.syncInputWindows) {
+        // If the caller requested to sync input windows, but there are no
+        // changes to input windows, notify immediately.
+        windowInfosReported();
+    }
+
+    for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
+        mInputFlinger->setFocusedWindow(focusRequest);
+    }
     mInputWindowCommands.clear();
 }
 
-void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
-                                      std::vector<DisplayInfo>& outDisplayInfos) {
+void SurfaceFlinger::notifyWindowInfos() {
+    std::vector<WindowInfo> windowInfos;
+    std::vector<DisplayInfo> displayInfos;
     std::unordered_map<uint32_t /*layerStackId*/,
                        std::pair<bool /* isSecure */, const ui::Transform>>
             inputDisplayDetails;
+
     for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
         if (!display->receivesInput()) {
             continue;
@@ -3102,7 +3089,7 @@
                   layerStackId);
             continue;
         }
-        outDisplayInfos.emplace_back(info);
+        displayInfos.emplace_back(info);
     }
 
     mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
@@ -3122,8 +3109,10 @@
                   layer->getDebugName(), layerStackId);
         }
 
-        outWindowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure));
+        windowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure));
     });
+    mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
+                                                    mInputWindowCommands.syncInputWindows);
 }
 
 void SurfaceFlinger::updateCursorAsync() {
@@ -3441,10 +3430,11 @@
         client->attachLayer(handle, lbc);
     }
 
+    int64_t transactionId = (((int64_t)mPid) << 32) | mUniqueTransactionId++;
     return setTransactionState(FrameTimelineInfo{}, states, displays, 0 /* flags */, nullptr,
                                InputWindowCommands{}, -1 /* desiredPresentTime */,
                                true /* isAutoTimestamp */, {}, false /* hasListenerCallbacks */, {},
-                               0 /* Undefined transactionId */);
+                               transactionId);
 }
 
 uint32_t SurfaceFlinger::getTransactionFlags() const {
@@ -3467,7 +3457,7 @@
     return old;
 }
 
-bool SurfaceFlinger::flushTransactionQueues() {
+bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) {
     // to prevent onHandleDestroyed from being called while the lock is held,
     // we must keep a copy of the transactions (specifically the composer
     // states) around outside the scope of the lock
@@ -3553,12 +3543,13 @@
                 ATRACE_INT("TransactionQueue", mTransactionQueue.size());
             }
 
-            return applyTransactions(transactions);
+            return applyTransactions(transactions, vsyncId);
         }
     }
 }
 
-bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions) {
+bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions,
+                                       int64_t vsyncId) {
     bool needsTraversal = false;
     // Now apply all transactions.
     for (const auto& transaction : transactions) {
@@ -3576,6 +3567,10 @@
                     std::move(transaction.transactionCommittedSignal));
         }
     }
+
+    if (mTransactionTracingEnabled) {
+        mTransactionTracing.addCommittedTransactions(transactions, vsyncId);
+    }
     return needsTraversal;
 }
 
@@ -3829,6 +3824,10 @@
     state.traverseStatesWithBuffers([&](const layer_state_t& state) {
         mBufferCountTracker.increment(state.surface->localBinder());
     });
+
+    if (mTransactionTracingEnabled) {
+        mTransactionTracing.addQueuedTransaction(state);
+    }
     queueTransaction(state);
 
     // Check the pending state to make sure the transaction is synchronous.
@@ -4408,6 +4407,16 @@
         return result;
     }
 
+    int parentId = -1;
+    // We can safely promote the layer in binder thread because we have a strong reference
+    // to the layer's handle inside this scope or we were passed in a sp reference to the layer.
+    sp<Layer> parentSp = parent.promote();
+    if (parentSp != nullptr) {
+        parentId = parentSp->getSequence();
+    }
+    mTransactionTracing.onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name,
+                                     args.flags, parentId);
+
     setTransactionFlags(eTransactionNeeded);
     *outLayerId = layer->sequence;
     return result;
@@ -4517,10 +4526,12 @@
     displays.add(d);
 
     nsecs_t now = systemTime();
+
+    int64_t transactionId = (((int64_t)mPid) << 32) | mUniqueTransactionId++;
     // It should be on the main thread, apply it directly.
     applyTransactionState(FrameTimelineInfo{}, state, displays, 0, mInputWindowCommands,
                           /* desiredPresentTime */ now, true, {}, /* postTime */ now, true, false,
-                          {}, getpid(), getuid(), 0 /* Undefined transactionId */);
+                          {}, mPid, getuid(), transactionId);
 
     setPowerModeInternal(display, hal::PowerMode::ON);
     const nsecs_t vsyncPeriod =
@@ -4719,8 +4730,9 @@
 }
 
 status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) {
-    if (asProto && mLayerTracing.isEnabled()) {
+    if (asProto) {
         mLayerTracing.writeToFile();
+        mTransactionTracing.writeToFile();
     }
 
     return doDump(fd, DumpArgs(), asProto);
@@ -4917,7 +4929,6 @@
 }
 
 LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
-    // If context is SurfaceTracing thread, mTracingLock blocks display transactions on main thread.
     const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
 
     LayersProto layersProto;
@@ -5118,6 +5129,8 @@
      */
     mLayerTracing.dump(result);
     result.append("\n");
+    mTransactionTracing.dump(result);
+    result.append("\n");
 
     /*
      * HWC layer minidump
@@ -5350,9 +5363,9 @@
         code == IBinder::SYSPROPS_TRANSACTION) {
         return OK;
     }
-    // Numbers from 1000 to 1040 are currently used for backdoors. The code
+    // Numbers from 1000 to 1041 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 <= 1040) {
+    if (code >= 1000 && code <= 1041) {
         ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
         return OK;
     }
@@ -5791,6 +5804,20 @@
                 scheduleRepaint();
                 return NO_ERROR;
             }
+            case 1041: { // Transaction tracing
+                if (data.readInt32()) {
+                    // Transaction tracing is always running but allow the user to temporarily
+                    // increase the buffer when actively debugging.
+                    mTransactionTracing.setBufferSize(
+                            TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE);
+                } else {
+                    mTransactionTracing.setBufferSize(
+                            TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE);
+                    mTransactionTracing.writeToFile();
+                }
+                reply->writeInt32(NO_ERROR);
+                return NO_ERROR;
+            }
         }
     }
     return err;
@@ -6625,6 +6652,7 @@
     if (!layer->isRemovedFromCurrentState()) {
         mScheduler->deregisterLayer(layer);
     }
+    mTransactionTracing.onLayerRemoved(layer->getSequence());
 }
 
 void SurfaceFlinger::onLayerUpdate() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7355130..9794639 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -64,6 +64,7 @@
 #include "SurfaceFlingerFactory.h"
 #include "TracedOrdinal.h"
 #include "Tracing/LayerTracing.h"
+#include "Tracing/TransactionTracing.h"
 #include "TransactionCallbackInvoker.h"
 #include "TransactionState.h"
 
@@ -689,8 +690,7 @@
     void updateLayerGeometry();
 
     void updateInputFlinger();
-    void buildWindowInfos(std::vector<gui::WindowInfo>& outWindowInfos,
-                          std::vector<gui::DisplayInfo>& outDisplayInfos);
+    void notifyWindowInfos();
     void commitInputWindowCommands() REQUIRES(mStateLock);
     void updateCursorAsync();
 
@@ -712,7 +712,7 @@
                                int originPid, int originUid, uint64_t transactionId)
             REQUIRES(mStateLock);
     // flush pending transaction that was presented after desiredPresentTime.
-    bool flushTransactionQueues();
+    bool flushTransactionQueues(int64_t vsyncId);
     // Returns true if there is at least one transaction that needs to be flushed
     bool transactionFlushNeeded();
 
@@ -748,7 +748,8 @@
     bool allowedLatchUnsignaled() REQUIRES(mQueueLock, mStateLock);
     bool checkTransactionCanLatchUnsignaled(const TransactionState& transaction)
             REQUIRES(mStateLock);
-    bool applyTransactions(std::vector<TransactionState>& transactions) REQUIRES(mStateLock);
+    bool applyTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId)
+            REQUIRES(mStateLock);
     uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
     uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
             REQUIRES(mStateLock);
@@ -1083,7 +1084,7 @@
 
     sp<StartPropertySetThread> mStartPropertySetThread;
     surfaceflinger::Factory& mFactory;
-
+    pid_t mPid;
     std::future<void> mRenderEnginePrimeCacheFuture;
 
     // access must be protected by mStateLock
@@ -1092,6 +1093,7 @@
     std::atomic<int32_t> mTransactionFlags = 0;
     std::vector<std::shared_ptr<CountDownLatch>> mTransactionCommittedSignals;
     bool mAnimTransactionPending = false;
+    std::atomic<uint32_t> mUniqueTransactionId = 1;
     SortedVector<sp<Layer>> mLayersPendingRemoval;
 
     // global color transform states
@@ -1182,8 +1184,10 @@
     sp<SurfaceInterceptor> mInterceptor;
 
     LayerTracing mLayerTracing{*this};
-    std::mutex mTracingLock;
-    bool mTracingEnabled = false;
+    bool mLayerTracingEnabled = false;
+
+    TransactionTracing mTransactionTracing;
+    bool mTransactionTracingEnabled = false;
     std::atomic<bool> mTracingEnabledChanged = false;
 
     const std::shared_ptr<TimeStats> mTimeStats;
@@ -1290,7 +1294,6 @@
     const float mInternalDisplayDensity;
     const float mEmulatedDisplayDensity;
 
-    // Should only be accessed by BackgroundExecutor thread.
     sp<os::IInputFlinger> mInputFlinger;
     // Should only be accessed by the main thread.
     InputWindowCommands mInputWindowCommands;
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index 84890ee..d136e0b 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -53,6 +53,7 @@
     mEnabled = false;
     LayersTraceFileProto fileProto = createTraceFileProto();
     mBuffer->writeToFile(fileProto, FILE_NAME);
+    mBuffer->reset();
     return true;
 }
 
diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h
index d0fb3f2..281cd19 100644
--- a/services/surfaceflinger/Tracing/RingBuffer.h
+++ b/services/surfaceflinger/Tracing/RingBuffer.h
@@ -21,8 +21,9 @@
 
 #include <log/log.h>
 #include <utils/Errors.h>
-#include <utils/SystemClock.h>
+#include <utils/Timers.h>
 #include <utils/Trace.h>
+#include <chrono>
 #include <queue>
 
 namespace android {
@@ -38,27 +39,27 @@
     void setSize(size_t newSize) { mSizeInBytes = newSize; }
     EntryProto& front() { return mStorage.front(); }
     const EntryProto& front() const { return mStorage.front(); }
+    const EntryProto& back() const { return mStorage.back(); }
 
-    void reset(size_t newSize) {
+    void reset() {
         // use the swap trick to make sure memory is released
-        std::queue<EntryProto>().swap(mStorage);
-        mSizeInBytes = newSize;
+        std::deque<EntryProto>().swap(mStorage);
         mUsedInBytes = 0U;
     }
-    void flush(FileProto& fileProto) {
-        fileProto.mutable_entry()->Reserve(static_cast<int>(mStorage.size()));
-        while (!mStorage.empty()) {
-            auto entry = fileProto.add_entry();
-            entry->Swap(&mStorage.front());
-            mStorage.pop();
+
+    void writeToProto(FileProto& fileProto) {
+        fileProto.mutable_entry()->Reserve(static_cast<int>(mStorage.size()) +
+                                           fileProto.entry().size());
+        for (const EntryProto& entry : mStorage) {
+            EntryProto* entryProto = fileProto.add_entry();
+            *entryProto = entry;
         }
     }
 
     status_t writeToFile(FileProto& fileProto, std::string filename) {
         ATRACE_CALL();
+        writeToProto(fileProto);
         std::string output;
-        flush(fileProto);
-        reset(mSizeInBytes);
         if (!fileProto.SerializeToString(&output)) {
             ALOGE("Could not serialize proto.");
             return UNKNOWN_ERROR;
@@ -82,10 +83,10 @@
             }
             mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize());
             replacedEntries.emplace_back(mStorage.front());
-            mStorage.pop();
+            mStorage.pop_front();
         }
         mUsedInBytes += protoSize;
-        mStorage.emplace();
+        mStorage.emplace_back();
         mStorage.back().Swap(&proto);
         return replacedEntries;
     }
@@ -99,14 +100,14 @@
         const int64_t durationCount = duration.count();
         base::StringAppendF(&result,
                             "  number of entries: %zu (%.2fMB / %.2fMB) duration: %" PRIi64 "ms\n",
-                            frameCount(), float(used()) / 1024.f * 1024.f,
-                            float(size()) / 1024.f * 1024.f, durationCount);
+                            frameCount(), float(used()) / (1024.f * 1024.f),
+                            float(size()) / (1024.f * 1024.f), durationCount);
     }
 
 private:
     size_t mUsedInBytes = 0U;
     size_t mSizeInBytes = 0U;
-    std::queue<EntryProto> mStorage;
+    std::deque<EntryProto> mStorage;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index d1dc076..7e12313 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -43,7 +43,7 @@
 }
 
 proto::TransactionState TransactionProtoParser::toProto(
-        std::vector<std::pair<int32_t /* layerId */, TracingLayerState>> states) {
+        const std::unordered_map<int32_t /* layerId */, TracingLayerState> states) {
     proto::TransactionState proto;
     for (auto& [layerId, state] : states) {
         proto::LayerState layerProto = toProto(state, nullptr);
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index e8a139f..619ee05 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -51,7 +51,7 @@
     static proto::TransactionState toProto(const TransactionState&, LayerHandleToIdFn getLayerIdFn,
                                            DisplayHandleToIdFn getDisplayIdFn);
     static proto::TransactionState toProto(
-            std::vector<std::pair<int32_t /* layerId */, TracingLayerState>>);
+            const std::unordered_map<int32_t /* layerId */, TracingLayerState>);
 
     static proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
 
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
new file mode 100644
index 0000000..cf488c2
--- /dev/null
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "TransactionTracing"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+#include <utils/Trace.h>
+
+#include "RingBuffer.h"
+#include "TransactionTracing.h"
+
+namespace android {
+
+TransactionTracing::TransactionTracing() {
+    mBuffer = std::make_unique<
+            RingBuffer<proto::TransactionTraceFile, proto::TransactionTraceEntry>>();
+}
+
+TransactionTracing::~TransactionTracing() = default;
+
+bool TransactionTracing::enable() {
+    std::scoped_lock lock(mTraceLock);
+    if (mEnabled) {
+        return false;
+    }
+    mBuffer->setSize(mBufferSizeInBytes);
+    mStartingTimestamp = systemTime();
+    mEnabled = true;
+    {
+        std::scoped_lock lock(mMainThreadLock);
+        mDone = false;
+        mThread = std::thread(&TransactionTracing::loop, this);
+    }
+    return true;
+}
+
+bool TransactionTracing::disable() {
+    std::thread thread;
+    {
+        std::scoped_lock lock(mMainThreadLock);
+        mDone = true;
+        mTransactionsAvailableCv.notify_all();
+        thread = std::move(mThread);
+    }
+    if (thread.joinable()) {
+        thread.join();
+    }
+
+    std::scoped_lock lock(mTraceLock);
+    if (!mEnabled) {
+        return false;
+    }
+    mEnabled = false;
+
+    writeToFileLocked();
+    mBuffer->reset();
+    mQueuedTransactions.clear();
+    mStartingStates.clear();
+    mLayerHandles.clear();
+    return true;
+}
+
+bool TransactionTracing::isEnabled() const {
+    std::scoped_lock lock(mTraceLock);
+    return mEnabled;
+}
+
+status_t TransactionTracing::writeToFile() {
+    std::scoped_lock lock(mTraceLock);
+    if (!mEnabled) {
+        return STATUS_OK;
+    }
+    return writeToFileLocked();
+}
+
+status_t TransactionTracing::writeToFileLocked() {
+    proto::TransactionTraceFile fileProto = createTraceFileProto();
+    addStartingStateToProtoLocked(fileProto);
+    return mBuffer->writeToFile(fileProto, FILE_NAME);
+}
+
+void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) {
+    std::scoped_lock lock(mTraceLock);
+    mBufferSizeInBytes = bufferSizeInBytes;
+    mBuffer->setSize(mBufferSizeInBytes);
+}
+
+proto::TransactionTraceFile TransactionTracing::createTraceFileProto() const {
+    proto::TransactionTraceFile proto;
+    proto.set_magic_number(uint64_t(proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_H) << 32 |
+                           proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_L);
+    return proto;
+}
+
+void TransactionTracing::dump(std::string& result) const {
+    std::scoped_lock lock(mTraceLock);
+    base::StringAppendF(&result, "Transaction tracing state: %s\n",
+                        mEnabled ? "enabled" : "disabled");
+    base::StringAppendF(&result,
+                        "  queued transactions=%zu created layers=%zu handles=%zu states=%zu\n",
+                        mQueuedTransactions.size(), mCreatedLayers.size(), mLayerHandles.size(),
+                        mStartingStates.size());
+    mBuffer->dump(result);
+}
+
+void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
+    std::scoped_lock lock(mTraceLock);
+    ATRACE_CALL();
+    if (!mEnabled) {
+        return;
+    }
+    mQueuedTransactions[transaction.id] =
+            TransactionProtoParser::toProto(transaction,
+                                            std::bind(&TransactionTracing::getLayerIdLocked, this,
+                                                      std::placeholders::_1),
+                                            nullptr);
+}
+
+void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
+                                                  int64_t vsyncId) {
+    CommittedTransactions committedTransactions;
+    committedTransactions.vsyncId = vsyncId;
+    committedTransactions.timestamp = systemTime();
+    committedTransactions.transactionIds.reserve(transactions.size());
+    for (const auto& transaction : transactions) {
+        committedTransactions.transactionIds.emplace_back(transaction.id);
+    }
+
+    mPendingTransactions.emplace_back(committedTransactions);
+    tryPushToTracingThread();
+}
+
+void TransactionTracing::loop() {
+    while (true) {
+        std::vector<CommittedTransactions> committedTransactions;
+        std::vector<int32_t> removedLayers;
+        {
+            std::unique_lock<std::mutex> lock(mMainThreadLock);
+            base::ScopedLockAssertion assumeLocked(mMainThreadLock);
+            mTransactionsAvailableCv.wait(lock, [&]() REQUIRES(mMainThreadLock) {
+                return mDone || !mCommittedTransactions.empty();
+            });
+            if (mDone) {
+                mCommittedTransactions.clear();
+                mRemovedLayers.clear();
+                break;
+            }
+
+            removedLayers = std::move(mRemovedLayers);
+            mRemovedLayers.clear();
+            committedTransactions = std::move(mCommittedTransactions);
+            mCommittedTransactions.clear();
+        } // unlock mMainThreadLock
+
+        addEntry(committedTransactions, removedLayers);
+    }
+}
+
+void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& committedTransactions,
+                                  const std::vector<int32_t>& removedLayers) {
+    ATRACE_CALL();
+    std::scoped_lock lock(mTraceLock);
+    std::vector<proto::TransactionTraceEntry> removedEntries;
+    for (const CommittedTransactions& entry : committedTransactions) {
+        proto::TransactionTraceEntry entryProto;
+        entryProto.set_elapsed_realtime_nanos(entry.timestamp);
+        entryProto.set_vsync_id(entry.vsyncId);
+        entryProto.mutable_added_layers()->Reserve(static_cast<int32_t>(mCreatedLayers.size()));
+        for (auto& newLayer : mCreatedLayers) {
+            entryProto.mutable_added_layers()->Add(std::move(newLayer));
+        }
+        entryProto.mutable_removed_layers()->Reserve(static_cast<int32_t>(removedLayers.size()));
+        for (auto& removedLayer : removedLayers) {
+            entryProto.mutable_removed_layers()->Add(removedLayer);
+        }
+        mCreatedLayers.clear();
+        entryProto.mutable_transactions()->Reserve(
+                static_cast<int32_t>(entry.transactionIds.size()));
+        for (const uint64_t& id : entry.transactionIds) {
+            auto it = mQueuedTransactions.find(id);
+            if (it != mQueuedTransactions.end()) {
+                entryProto.mutable_transactions()->Add(std::move(it->second));
+                mQueuedTransactions.erase(it);
+            } else {
+                ALOGE("Could not find transaction id %" PRIu64, id);
+            }
+        }
+        std::vector<proto::TransactionTraceEntry> entries = mBuffer->emplace(std::move(entryProto));
+        removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()),
+                              std::make_move_iterator(entries.end()));
+    }
+
+    for (const proto::TransactionTraceEntry& removedEntry : removedEntries) {
+        updateStartingStateLocked(removedEntry);
+    }
+    mTransactionsAddedToBufferCv.notify_one();
+}
+
+void TransactionTracing::flush(int64_t vsyncId) {
+    while (!mPendingTransactions.empty() || !mPendingRemovedLayers.empty()) {
+        tryPushToTracingThread();
+    }
+    std::unique_lock<std::mutex> lock(mTraceLock);
+    base::ScopedLockAssertion assumeLocked(mTraceLock);
+    mTransactionsAddedToBufferCv.wait(lock, [&]() REQUIRES(mTraceLock) {
+        return mBuffer->used() > 0 && mBuffer->back().vsync_id() >= vsyncId;
+    });
+}
+
+void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name,
+                                      uint32_t flags, int parentId) {
+    std::scoped_lock lock(mTraceLock);
+    TracingLayerCreationArgs args{layerId, name, flags, parentId};
+    mLayerHandles[layerHandle] = layerId;
+    mCreatedLayers.emplace_back(TransactionProtoParser::toProto(args));
+}
+
+void TransactionTracing::onLayerRemoved(int32_t layerId) {
+    mPendingRemovedLayers.emplace_back(layerId);
+    tryPushToTracingThread();
+}
+
+void TransactionTracing::tryPushToTracingThread() {
+    // Try to acquire the lock from main thread.
+    if (mMainThreadLock.try_lock()) {
+        // We got the lock! Collect any pending transactions and continue.
+        mCommittedTransactions.insert(mCommittedTransactions.end(),
+                                      std::make_move_iterator(mPendingTransactions.begin()),
+                                      std::make_move_iterator(mPendingTransactions.end()));
+        mPendingTransactions.clear();
+        mRemovedLayers.insert(mRemovedLayers.end(), mPendingRemovedLayers.begin(),
+                              mPendingRemovedLayers.end());
+        mPendingRemovedLayers.clear();
+        mTransactionsAvailableCv.notify_one();
+        mMainThreadLock.unlock();
+    } else {
+        ALOGV("Couldn't get lock");
+    }
+}
+
+int32_t TransactionTracing::getLayerIdLocked(const sp<IBinder>& layerHandle) {
+    if (layerHandle == nullptr) {
+        return -1;
+    }
+    auto it = mLayerHandles.find(layerHandle->localBinder());
+    return it == mLayerHandles.end() ? -1 : it->second;
+}
+
+void TransactionTracing::updateStartingStateLocked(
+        const proto::TransactionTraceEntry& removedEntry) {
+    // Keep track of layer starting state so we can reconstruct the layer state as we purge
+    // transactions from the buffer.
+    for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) {
+        TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()];
+        startingState.layerId = addedLayer.layer_id();
+        startingState.name = addedLayer.name();
+        startingState.layerCreationFlags = addedLayer.flags();
+        startingState.parentId = addedLayer.parent_id();
+    }
+
+    // Merge layer states to starting transaction state.
+    for (const proto::TransactionState& transaction : removedEntry.transactions()) {
+        for (const proto::LayerState& layerState : transaction.layer_changes()) {
+            auto it = mStartingStates.find(layerState.layer_id());
+            if (it == mStartingStates.end()) {
+                ALOGE("Could not find layer id %d", layerState.layer_id());
+                continue;
+            }
+            TransactionProtoParser::fromProto(layerState, nullptr, it->second);
+        }
+    }
+
+    // Clean up stale starting states since the layer has been removed and the buffer does not
+    // contain any references to the layer.
+    for (const int32_t removedLayerId : removedEntry.removed_layers()) {
+        auto it = std::find_if(mLayerHandles.begin(), mLayerHandles.end(),
+                               [removedLayerId](auto& layer) {
+                                   return layer.second == removedLayerId;
+                               });
+        if (it != mLayerHandles.end()) {
+            mLayerHandles.erase(it);
+        }
+        mStartingStates.erase(removedLayerId);
+    }
+}
+
+void TransactionTracing::addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) {
+    proto::TransactionTraceEntry* entryProto = proto.add_entry();
+    entryProto->set_elapsed_realtime_nanos(mStartingTimestamp);
+    entryProto->set_vsync_id(0);
+    entryProto->mutable_added_layers()->Reserve(static_cast<int32_t>(mStartingStates.size()));
+    for (auto& [layerId, state] : mStartingStates) {
+        TracingLayerCreationArgs args{layerId, state.name, state.layerCreationFlags,
+                                      state.parentId};
+        entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(args));
+    }
+
+    proto::TransactionState transactionProto = TransactionProtoParser::toProto(mStartingStates);
+    transactionProto.set_vsync_id(0);
+    transactionProto.set_post_time(mStartingTimestamp);
+    entryProto->mutable_transactions()->Add(std::move(transactionProto));
+}
+
+proto::TransactionTraceFile TransactionTracing::writeToProto() {
+    std::scoped_lock<std::mutex> lock(mTraceLock);
+    proto::TransactionTraceFile proto = createTraceFileProto();
+    addStartingStateToProtoLocked(proto);
+    mBuffer->writeToProto(proto);
+    return proto;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
new file mode 100644
index 0000000..0aa22ed
--- /dev/null
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <layerproto/TransactionProto.h>
+#include <utils/Errors.h>
+#include <utils/Timers.h>
+
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include "TransactionProtoParser.h"
+
+using namespace android::surfaceflinger;
+
+namespace android {
+
+template <typename FileProto, typename EntryProto>
+class RingBuffer;
+
+class SurfaceFlinger;
+class TransactionTracingTest;
+/*
+ * Records all committed transactions into a ring bufffer.
+ *
+ * Transactions come in via the binder thread. They are serialized to proto
+ * and stored in a map using the transaction id as key. Main thread will
+ * pass the list of transaction ids that are committed every vsync and notify
+ * the tracing thread. The tracing thread will then wake up and add the
+ * committed transactions to the ring buffer.
+ *
+ * When generating SF dump state, we will flush the buffer to a file which
+ * will then be included in the bugreport.
+ *
+ */
+class TransactionTracing {
+public:
+    TransactionTracing();
+    ~TransactionTracing();
+
+    bool enable();
+    bool disable();
+    bool isEnabled() const;
+
+    void addQueuedTransaction(const TransactionState&);
+    void addCommittedTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId);
+    status_t writeToFile();
+    void setBufferSize(size_t bufferSizeInBytes);
+    void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags,
+                      int parentId);
+    void onLayerRemoved(int layerId);
+    void dump(std::string&) const;
+    static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024;
+    static constexpr auto ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024;
+
+private:
+    friend class TransactionTracingTest;
+
+    static constexpr auto FILE_NAME = "/data/misc/wmtrace/transactions_trace.winscope";
+
+    mutable std::mutex mTraceLock;
+    bool mEnabled GUARDED_BY(mTraceLock) = false;
+    std::unique_ptr<RingBuffer<proto::TransactionTraceFile, proto::TransactionTraceEntry>> mBuffer
+            GUARDED_BY(mTraceLock);
+    size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = CONTINUOUS_TRACING_BUFFER_SIZE;
+    std::unordered_map<uint64_t, proto::TransactionState> mQueuedTransactions
+            GUARDED_BY(mTraceLock);
+    nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock);
+    std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
+    std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles
+            GUARDED_BY(mTraceLock);
+    std::unordered_map<int32_t /* layerId */, TracingLayerState> mStartingStates
+            GUARDED_BY(mTraceLock);
+
+    // We do not want main thread to block so main thread will try to acquire mMainThreadLock,
+    // otherwise will push data to temporary container.
+    std::mutex mMainThreadLock;
+    std::thread mThread GUARDED_BY(mMainThreadLock);
+    bool mDone GUARDED_BY(mMainThreadLock) = false;
+    std::condition_variable mTransactionsAvailableCv;
+    std::condition_variable mTransactionsAddedToBufferCv;
+    struct CommittedTransactions {
+        std::vector<uint64_t> transactionIds;
+        int64_t vsyncId;
+        int64_t timestamp;
+    };
+    std::vector<CommittedTransactions> mCommittedTransactions GUARDED_BY(mMainThreadLock);
+    std::vector<CommittedTransactions> mPendingTransactions; // only accessed by main thread
+
+    std::vector<int32_t /* layerId */> mRemovedLayers GUARDED_BY(mMainThreadLock);
+    std::vector<int32_t /* layerId */> mPendingRemovedLayers; // only accessed by main thread
+
+    proto::TransactionTraceFile createTraceFileProto() const;
+    void loop();
+    void addEntry(const std::vector<CommittedTransactions>& committedTransactions,
+                  const std::vector<int32_t>& removedLayers) EXCLUDES(mTraceLock);
+    int32_t getLayerIdLocked(const sp<IBinder>& layerHandle) REQUIRES(mTraceLock);
+    void tryPushToTracingThread() EXCLUDES(mMainThreadLock);
+    void addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) REQUIRES(mTraceLock);
+    void updateStartingStateLocked(const proto::TransactionTraceEntry& entry) REQUIRES(mTraceLock);
+    status_t writeToFileLocked() REQUIRES(mTraceLock);
+
+    // TEST
+    // Wait until all the committed transactions for the specified vsync id are added to the buffer.
+    void flush(int64_t vsyncId) EXCLUDES(mMainThreadLock);
+    // Return buffer contents as trace file proto
+    proto::TransactionTraceFile writeToProto() EXCLUDES(mMainThreadLock);
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index edeacfa..10222cc 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -42,8 +42,10 @@
     int64 elapsed_realtime_nanos = 1;
     int64 vsync_id = 2;
     repeated TransactionState transactions = 3;
-    repeated LayerCreationArgs new_layers = 4;
-    repeated DisplayState new_displays = 5;
+    repeated LayerCreationArgs added_layers = 4;
+    repeated int32 removed_layers = 5;
+    repeated DisplayState added_displays = 6;
+    repeated int32 removed_displays = 7;
 }
 
 message LayerCreationArgs {
diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
index 0069111..bb52245 100644
--- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp
+++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
@@ -112,11 +112,12 @@
     sp<SurfaceControl> surfaceControl =
             mClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888,
                                    ISurfaceComposerClient::eFXSurfaceBufferState);
-
+    const Rect crop(0, 0, 100, 100);
     Transaction()
             .setLayerStack(surfaceControl, ui::DEFAULT_LAYER_STACK)
             .show(surfaceControl)
             .setLayer(surfaceControl, INT32_MAX - 1)
+            .setCrop(surfaceControl, crop)
             .setInputWindowInfo(surfaceControl, windowInfo)
             .apply();
 
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 5f47a1a..561d9e2 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -94,6 +94,7 @@
         "TransactionFrameTracerTest.cpp",
         "TransactionProtoParserTest.cpp",
         "TransactionSurfaceFrameTest.cpp",
+        "TransactionTracingTest.cpp",
         "TunnelModeEnabledReporterTest.cpp",
         "StrongTypingTest.cpp",
         "VSyncDispatchTimerQueueTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 7f949b9..100a78d 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -388,7 +388,7 @@
                                              listenerCallbacks, transactionId);
     }
 
-    auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
+    auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(0); };
 
     auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
         return mFlinger->onTransact(code, data, reply, flags);
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
new file mode 100644
index 0000000..ffe5671
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <gui/SurfaceComposerClient.h>
+
+#include "Tracing/RingBuffer.h"
+#include "Tracing/TransactionTracing.h"
+
+using namespace android::surfaceflinger;
+
+namespace android {
+
+class TransactionTracingTest : public testing::Test {
+protected:
+    static constexpr size_t SMALL_BUFFER_SIZE = 1024;
+    std::unique_ptr<android::TransactionTracing> mTracing;
+    void SetUp() override { mTracing = std::make_unique<android::TransactionTracing>(); }
+
+    void TearDown() override {
+        mTracing->disable();
+        mTracing.reset();
+    }
+
+    auto getCommittedTransactions() {
+        std::scoped_lock<std::mutex> lock(mTracing->mMainThreadLock);
+        return mTracing->mCommittedTransactions;
+    }
+
+    auto getQueuedTransactions() {
+        std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
+        return mTracing->mQueuedTransactions;
+    }
+
+    auto getUsedBufferSize() {
+        std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
+        return mTracing->mBuffer->used();
+    }
+
+    auto flush(int64_t vsyncId) { return mTracing->flush(vsyncId); }
+
+    auto bufferFront() {
+        std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
+        return mTracing->mBuffer->front();
+    }
+
+    bool threadIsJoinable() {
+        std::scoped_lock lock(mTracing->mMainThreadLock);
+        return mTracing->mThread.joinable();
+    }
+
+    proto::TransactionTraceFile writeToProto() { return mTracing->writeToProto(); }
+
+    auto getCreatedLayers() {
+        std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
+        return mTracing->mCreatedLayers;
+    }
+
+    auto getStartingStates() {
+        std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
+        return mTracing->mStartingStates;
+    }
+
+    void queueAndCommitTransaction(int64_t vsyncId) {
+        TransactionState transaction;
+        transaction.id = static_cast<uint64_t>(vsyncId * 3);
+        transaction.originUid = 1;
+        transaction.originPid = 2;
+        mTracing->addQueuedTransaction(transaction);
+        std::vector<TransactionState> transactions;
+        transactions.emplace_back(transaction);
+        mTracing->addCommittedTransactions(transactions, vsyncId);
+        flush(vsyncId);
+    }
+
+    // Test that we clean up the tracing thread and free any memory allocated.
+    void verifyDisabledTracingState() {
+        EXPECT_FALSE(mTracing->isEnabled());
+        EXPECT_FALSE(threadIsJoinable());
+        EXPECT_EQ(getCommittedTransactions().size(), 0u);
+        EXPECT_EQ(getQueuedTransactions().size(), 0u);
+        EXPECT_EQ(getUsedBufferSize(), 0u);
+        EXPECT_EQ(getStartingStates().size(), 0u);
+    }
+
+    void verifyEntry(const proto::TransactionTraceEntry& actualProto,
+                     const std::vector<TransactionState> expectedTransactions,
+                     int64_t expectedVsyncId) {
+        EXPECT_EQ(actualProto.vsync_id(), expectedVsyncId);
+        EXPECT_EQ(actualProto.transactions().size(),
+                  static_cast<int32_t>(expectedTransactions.size()));
+        for (uint32_t i = 0; i < expectedTransactions.size(); i++) {
+            EXPECT_EQ(actualProto.transactions(static_cast<int32_t>(i)).pid(),
+                      expectedTransactions[i].originPid);
+        }
+    }
+};
+
+TEST_F(TransactionTracingTest, enable) {
+    EXPECT_FALSE(mTracing->isEnabled());
+    mTracing->enable();
+    EXPECT_TRUE(mTracing->isEnabled());
+    mTracing->disable();
+    verifyDisabledTracingState();
+}
+
+TEST_F(TransactionTracingTest, addTransactions) {
+    mTracing->enable();
+    std::vector<TransactionState> transactions;
+    transactions.reserve(100);
+    for (uint64_t i = 0; i < 100; i++) {
+        TransactionState transaction;
+        transaction.id = i;
+        transaction.originPid = static_cast<int32_t>(i);
+        transactions.emplace_back(transaction);
+        mTracing->addQueuedTransaction(transaction);
+    }
+
+    // Split incoming transactions into two and commit them in reverse order to test out of order
+    // commits.
+    std::vector<TransactionState> firstTransactionSet =
+            std::vector<TransactionState>(transactions.begin() + 50, transactions.end());
+    int64_t firstTransactionSetVsyncId = 42;
+    mTracing->addCommittedTransactions(firstTransactionSet, firstTransactionSetVsyncId);
+
+    int64_t secondTransactionSetVsyncId = 43;
+    std::vector<TransactionState> secondTransactionSet =
+            std::vector<TransactionState>(transactions.begin(), transactions.begin() + 50);
+    mTracing->addCommittedTransactions(secondTransactionSet, secondTransactionSetVsyncId);
+    flush(secondTransactionSetVsyncId);
+
+    proto::TransactionTraceFile proto = writeToProto();
+    EXPECT_EQ(proto.entry().size(), 3);
+    // skip starting entry
+    verifyEntry(proto.entry(1), firstTransactionSet, firstTransactionSetVsyncId);
+    verifyEntry(proto.entry(2), secondTransactionSet, secondTransactionSetVsyncId);
+
+    mTracing->disable();
+    verifyDisabledTracingState();
+}
+
+class TransactionTracingLayerHandlingTest : public TransactionTracingTest {
+protected:
+    void SetUp() override {
+        TransactionTracingTest::SetUp();
+        mTracing->enable();
+        // add layers
+        mTracing->setBufferSize(SMALL_BUFFER_SIZE);
+        const sp<IBinder> fakeLayerHandle = new BBinder();
+        mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent",
+                               123 /* flags */, -1 /* parentId */);
+        const sp<IBinder> fakeChildLayerHandle = new BBinder();
+        mTracing->onLayerAdded(fakeChildLayerHandle->localBinder(), 2 /* layerId */, "child",
+                               456 /* flags */, mParentLayerId);
+
+        // add some layer transaction
+        {
+            TransactionState transaction;
+            transaction.id = 50;
+            ComposerState layerState;
+            layerState.state.surface = fakeLayerHandle;
+            layerState.state.what = layer_state_t::eLayerChanged;
+            layerState.state.z = 42;
+            transaction.states.add(layerState);
+            ComposerState childState;
+            childState.state.surface = fakeChildLayerHandle;
+            layerState.state.z = 43;
+            transaction.states.add(childState);
+            mTracing->addQueuedTransaction(transaction);
+
+            std::vector<TransactionState> transactions;
+            transactions.emplace_back(transaction);
+            VSYNC_ID_FIRST_LAYER_CHANGE = ++mVsyncId;
+            mTracing->addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE);
+            flush(VSYNC_ID_FIRST_LAYER_CHANGE);
+        }
+
+        // add transactions that modify the layer state further so we can test that layer state
+        // gets merged
+        {
+            TransactionState transaction;
+            transaction.id = 51;
+            ComposerState layerState;
+            layerState.state.surface = fakeLayerHandle;
+            layerState.state.what = layer_state_t::eLayerChanged | layer_state_t::ePositionChanged;
+            layerState.state.z = 41;
+            layerState.state.x = 22;
+            transaction.states.add(layerState);
+            mTracing->addQueuedTransaction(transaction);
+
+            std::vector<TransactionState> transactions;
+            transactions.emplace_back(transaction);
+            VSYNC_ID_SECOND_LAYER_CHANGE = ++mVsyncId;
+            mTracing->addCommittedTransactions(transactions, VSYNC_ID_SECOND_LAYER_CHANGE);
+            flush(VSYNC_ID_SECOND_LAYER_CHANGE);
+        }
+
+        // remove child layer
+        mTracing->onLayerRemoved(2);
+        VSYNC_ID_CHILD_LAYER_REMOVED = ++mVsyncId;
+        queueAndCommitTransaction(VSYNC_ID_CHILD_LAYER_REMOVED);
+
+        // remove layer
+        mTracing->onLayerRemoved(1);
+        queueAndCommitTransaction(++mVsyncId);
+    }
+
+    void TearDown() override {
+        mTracing->disable();
+        verifyDisabledTracingState();
+        TransactionTracingTest::TearDown();
+    }
+
+    int mParentLayerId = 1;
+    int64_t mVsyncId = 0;
+    int64_t VSYNC_ID_FIRST_LAYER_CHANGE;
+    int64_t VSYNC_ID_SECOND_LAYER_CHANGE;
+    int64_t VSYNC_ID_CHILD_LAYER_REMOVED;
+};
+
+TEST_F(TransactionTracingLayerHandlingTest, addStartingState) {
+    // add transactions until we drop the transaction with the first layer change
+    while (bufferFront().vsync_id() <= VSYNC_ID_FIRST_LAYER_CHANGE) {
+        queueAndCommitTransaction(++mVsyncId);
+    }
+    proto::TransactionTraceFile proto = writeToProto();
+    // verify we can still retrieve the layer change from the first entry containing starting
+    // states.
+    EXPECT_GT(proto.entry().size(), 0);
+    EXPECT_GT(proto.entry(0).transactions().size(), 0);
+    EXPECT_GT(proto.entry(0).added_layers().size(), 0);
+    EXPECT_GT(proto.entry(0).transactions(0).layer_changes().size(), 0);
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 42);
+}
+
+TEST_F(TransactionTracingLayerHandlingTest, updateStartingState) {
+    // add transactions until we drop the transaction with the second layer change
+    while (bufferFront().vsync_id() <= VSYNC_ID_SECOND_LAYER_CHANGE) {
+        queueAndCommitTransaction(++mVsyncId);
+    }
+    proto::TransactionTraceFile proto = writeToProto();
+    // verify starting states are updated correctly
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 41);
+}
+
+TEST_F(TransactionTracingLayerHandlingTest, removeStartingState) {
+    // add transactions until we drop the transaction which removes the child layer
+    while (bufferFront().vsync_id() <= VSYNC_ID_CHILD_LAYER_REMOVED) {
+        queueAndCommitTransaction(++mVsyncId);
+    }
+    proto::TransactionTraceFile proto = writeToProto();
+    // verify the child layer has been removed from the trace
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 1);
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
+}
+
+TEST_F(TransactionTracingLayerHandlingTest, startingStateSurvivesBufferFlush) {
+    // add transactions until we drop the transaction with the second layer change
+    while (bufferFront().vsync_id() <= VSYNC_ID_SECOND_LAYER_CHANGE) {
+        queueAndCommitTransaction(++mVsyncId);
+    }
+    proto::TransactionTraceFile proto = writeToProto();
+    // verify we have two starting states
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2);
+
+    // Continue adding transactions until child layer is removed
+    while (bufferFront().vsync_id() <= VSYNC_ID_CHILD_LAYER_REMOVED) {
+        queueAndCommitTransaction(++mVsyncId);
+    }
+    proto = writeToProto();
+    // verify we still have the parent layer state
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 1);
+    EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
+}
+
+} // namespace android
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index d1cd397..fa3b260 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -965,6 +965,13 @@
     VkResult result = EnumerateDeviceExtensionProperties(physical_dev, nullptr,
                                                          &count, nullptr);
     if (result == VK_SUCCESS && count) {
+        // Work-around a race condition during Android start-up, that can result
+        // in the second call to EnumerateDeviceExtensionProperties having
+        // another extension.  That causes the second call to return
+        // VK_INCOMPLETE.  A work-around is to add 1 to "count" and ask for one
+        // more extension property.  See: http://anglebug.com/6715 and
+        // internal-to-Google b/206733351.
+        count++;
         driver_extensions_ = AllocateDriverExtensionArray(count);
         result = (driver_extensions_)
                      ? EnumerateDeviceExtensionProperties(
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 54b10b1..b5a0bdf 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -537,30 +537,6 @@
     }
 }
 
-int get_min_buffer_count(ANativeWindow* window,
-                         uint32_t* out_min_buffer_count) {
-    constexpr int kExtraBuffers = 2;
-
-    int err;
-    int min_undequeued_buffers;
-    err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-                        &min_undequeued_buffers);
-    if (err != android::OK || min_undequeued_buffers < 0) {
-        ALOGE(
-            "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) "
-            "value=%d",
-            strerror(-err), err, min_undequeued_buffers);
-        if (err == android::OK) {
-            err = android::UNKNOWN_ERROR;
-        }
-        return err;
-    }
-
-    *out_min_buffer_count =
-        static_cast<uint32_t>(min_undequeued_buffers + kExtraBuffers);
-    return android::OK;
-}
-
 }  // anonymous namespace
 
 VKAPI_ATTR
@@ -675,7 +651,7 @@
               strerror(-err), err);
         return VK_ERROR_SURFACE_LOST_KHR;
     }
-    capabilities->minImageCount = max_buffer_count == 1 ? 1 : 2;
+    capabilities->minImageCount = std::min(max_buffer_count, 3);
     capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
 
     capabilities->currentExtent =
@@ -877,13 +853,18 @@
 
     int err;
     int query_value;
-    uint32_t min_buffer_count;
     ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
 
-    err = get_min_buffer_count(window, &min_buffer_count);
-    if (err != android::OK) {
+    err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                        &query_value);
+    if (err != android::OK || query_value < 0) {
+        ALOGE(
+            "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) "
+            "value=%d",
+            strerror(-err), err, query_value);
         return VK_ERROR_SURFACE_LOST_KHR;
     }
+    uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
 
     err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
     if (err != android::OK || query_value < 0) {
@@ -894,7 +875,7 @@
     uint32_t max_buffer_count = static_cast<uint32_t>(query_value);
 
     std::vector<VkPresentModeKHR> present_modes;
-    if (min_buffer_count < max_buffer_count)
+    if (min_undequeued_buffers + 1 < max_buffer_count)
         present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
     present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
 
@@ -1215,14 +1196,19 @@
         }
     }
 
-    uint32_t min_buffer_count;
-    err = get_min_buffer_count(window, &min_buffer_count);
-    if (err != android::OK) {
+    int query_value;
+    err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                        &query_value);
+    if (err != android::OK || query_value < 0) {
+        ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
+              query_value);
         return VK_ERROR_SURFACE_LOST_KHR;
     }
-
-    uint32_t num_images =
-        std::max(min_buffer_count, create_info->minImageCount);
+    uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
+    const auto mailbox_num_images = std::max(3u, create_info->minImageCount);
+    const auto requested_images =
+        swap_interval ? create_info->minImageCount : mailbox_num_images;
+    uint32_t num_images = requested_images - 1 + min_undequeued_buffers;
 
     // Lower layer insists that we have at least two buffers. This is wasteful
     // and we'd like to relax it in the shared case, but not all the pieces are
@@ -1236,12 +1222,6 @@
         return VK_ERROR_SURFACE_LOST_KHR;
     }
 
-    // In shared mode the num_images must be one regardless of how many
-    // buffers were allocated for the buffer queue.
-    if (swapchain_image_usage & VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID) {
-        num_images = 1;
-    }
-
     int32_t legacy_usage = 0;
     if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
         uint64_t consumer_usage, producer_usage;