Merge "SF: Add support for boundless layers 1/2"
diff --git a/libs/gui/CleanSpec.mk b/CleanSpec.mk
similarity index 70%
rename from libs/gui/CleanSpec.mk
rename to CleanSpec.mk
index 5a5144c..1855d26 100644
--- a/libs/gui/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 The Android Open Source Project
+# Copyright (C) 2018 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -34,19 +34,23 @@
 # made today requires touching the same file, just copy the old
 # touch step and add it to the end of the list.
 #
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
 
 # For example:
 #$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
 #$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
 #$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
 #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libdvr.so" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
 $(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libgui*" -print0 | xargs -0 rm -f)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/thermalserviced)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/thermalservice.rc)
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 16abc1e..08218b8 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -6,8 +6,10 @@
 clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
                libs/graphicsenv/
                libs/gui/
+               libs/renderengine/
                libs/ui/
                libs/vr/
+               services/bufferhub/
                services/surfaceflinger/
                services/vr/
 
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index d950b7c..d6ca0bf 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -91,7 +91,12 @@
     chmod 0666 /sys/kernel/tracing/events/sync/enable
     chmod 0666 /sys/kernel/debug/tracing/events/fence/enable
     chmod 0666 /sys/kernel/tracing/events/fence/enable
-
+    chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/enable
+    chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow/enable
+    chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_grow/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink/enable
+    chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_shrink/enable
 
     # disk
     chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 260ea4b..71658d8 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -87,27 +87,27 @@
 status_t DumpstateService::dump(int fd, const Vector<String16>&) {
     dprintf(fd, "id: %d\n", ds_.id_);
     dprintf(fd, "pid: %d\n", ds_.pid_);
-    dprintf(fd, "update_progress: %s\n", ds_.update_progress_ ? "true" : "false");
+    dprintf(fd, "update_progress: %s\n", ds_.options_->do_progress_updates ? "true" : "false");
     dprintf(fd, "update_progress_threshold: %d\n", ds_.update_progress_threshold_);
     dprintf(fd, "last_updated_progress: %d\n", ds_.last_updated_progress_);
     dprintf(fd, "progress:\n");
     ds_.progress_->Dump(fd, "  ");
-    dprintf(fd, "args: %s\n", ds_.args_.c_str());
-    dprintf(fd, "extra_options: %s\n", ds_.extra_options_.c_str());
+    dprintf(fd, "args: %s\n", ds_.options_->args.c_str());
+    dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
     dprintf(fd, "version: %s\n", ds_.version_.c_str());
     dprintf(fd, "bugreport_dir: %s\n", ds_.bugreport_dir_.c_str());
     dprintf(fd, "screenshot_path: %s\n", ds_.screenshot_path_.c_str());
     dprintf(fd, "log_path: %s\n", ds_.log_path_.c_str());
     dprintf(fd, "tmp_path: %s\n", ds_.tmp_path_.c_str());
     dprintf(fd, "path: %s\n", ds_.path_.c_str());
-    dprintf(fd, "extra_options: %s\n", ds_.extra_options_.c_str());
+    dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
     dprintf(fd, "base_name: %s\n", ds_.base_name_.c_str());
     dprintf(fd, "name: %s\n", ds_.name_.c_str());
     dprintf(fd, "now: %ld\n", ds_.now_);
     dprintf(fd, "is_zipping: %s\n", ds_.IsZipping() ? "true" : "false");
     dprintf(fd, "listener: %s\n", ds_.listener_name_.c_str());
-    dprintf(fd, "notification title: %s\n", ds_.notification_title.c_str());
-    dprintf(fd, "notification description: %s\n", ds_.notification_description.c_str());
+    dprintf(fd, "notification title: %s\n", ds_.options_->notification_title.c_str());
+    dprintf(fd, "notification description: %s\n", ds_.options_->notification_description.c_str());
 
     return NO_ERROR;
 }
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 17bb7c3..904c0e9 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -682,7 +682,7 @@
                    CommandOptions::WithTimeout(1).Always().Build());
     printf("Bugreport format version: %s\n", version_.c_str());
     printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
-           PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str());
+           PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
     printf("\n");
 }
 
@@ -1374,6 +1374,12 @@
     printf("========================================================\n");
     printf("== dumpstate: done (id %d)\n", ds.id_);
     printf("========================================================\n");
+
+    printf("========================================================\n");
+    printf("== Obtaining statsd metadata\n");
+    printf("========================================================\n");
+    // This differs from the usual dumpsys stats, which is the stats report data.
+    RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
 }
 
 /* Dumps state for the default case. Returns true if everything went fine. */
@@ -1623,7 +1629,7 @@
     printf("*** See dumpstate-board.txt entry ***\n");
 }
 
-static void ShowUsageAndExit(int exitCode = 1) {
+static void ShowUsageAndExit(int exit_code = 1) {
     fprintf(stderr,
             "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
             "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
@@ -1643,7 +1649,7 @@
             "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
             "shouldn't be used with -P)\n"
             "  -v: prints the dumpstate header and exit\n");
-    exit(exitCode);
+    exit(exit_code);
 }
 
 static void ExitOnInvalidArgs() {
@@ -1769,13 +1775,13 @@
  * if we are writing zip files and adds the version file.
  */
 static void PrepareToWriteToFile() {
-    const Dumpstate::DumpOptions& options = ds.options_;
-    ds.bugreport_dir_ = dirname(options.use_outfile.c_str());
+    ds.bugreport_dir_ = dirname(ds.options_->use_outfile.c_str());
     std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
     std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
-    ds.base_name_ = android::base::StringPrintf("%s-%s-%s", basename(options.use_outfile.c_str()),
-                                                device_name.c_str(), build_id.c_str());
-    if (options.do_add_date) {
+    ds.base_name_ =
+        android::base::StringPrintf("%s-%s-%s", basename(ds.options_->use_outfile.c_str()),
+                                    device_name.c_str(), build_id.c_str());
+    if (ds.options_->do_add_date) {
         char date[80];
         strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
         ds.name_ = date;
@@ -1783,13 +1789,13 @@
         ds.name_ = "undated";
     }
 
-    if (options.telephony_only) {
+    if (ds.options_->telephony_only) {
         ds.base_name_ += "-telephony";
-    } else if (options.wifi_only) {
+    } else if (ds.options_->wifi_only) {
         ds.base_name_ += "-wifi";
     }
 
-    if (options.do_fb) {
+    if (ds.options_->do_fb) {
         ds.screenshot_path_ = ds.GetPath(".png");
     }
     ds.tmp_path_ = ds.GetPath(".tmp");
@@ -1805,7 +1811,7 @@
         ds.bugreport_dir_.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
         ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
 
-    if (options.do_zip_file) {
+    if (ds.options_->do_zip_file) {
         ds.path_ = ds.GetPath(".zip");
         MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
         create_parent_dirs(ds.path_.c_str());
@@ -1824,7 +1830,6 @@
  * printing zipped file status, etc.
  */
 static void FinalizeFile() {
-    const Dumpstate::DumpOptions& options = ds.options_;
     /* check if user changed the suffix using system properties */
     std::string name =
         android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
@@ -1853,7 +1858,7 @@
     }
 
     bool do_text_file = true;
-    if (options.do_zip_file) {
+    if (ds.options_->do_zip_file) {
         if (!ds.FinishZipFile()) {
             MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
             do_text_file = true;
@@ -1880,7 +1885,7 @@
             ds.path_.clear();
         }
     }
-    if (options.use_control_socket) {
+    if (ds.options_->use_control_socket) {
         if (do_text_file) {
             dprintf(ds.control_socket_fd_,
                     "FAIL:could not create zip file, check %s "
@@ -1894,7 +1899,6 @@
 
 /* Broadcasts that we are done with the bugreport */
 static void SendBugreportFinishedBroadcast() {
-    const Dumpstate::DumpOptions& options = ds.options_;
     if (!ds.path_.empty()) {
         MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
         // clang-format off
@@ -1908,22 +1912,22 @@
              "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
         };
         // clang-format on
-        if (options.do_fb) {
+        if (ds.options_->do_fb) {
             am_args.push_back("--es");
             am_args.push_back("android.intent.extra.SCREENSHOT");
             am_args.push_back(ds.screenshot_path_);
         }
-        if (!ds.notification_title.empty()) {
+        if (ds.options_->notification_title.empty()) {
             am_args.push_back("--es");
             am_args.push_back("android.intent.extra.TITLE");
-            am_args.push_back(ds.notification_title);
-            if (!ds.notification_description.empty()) {
+            am_args.push_back(ds.options_->notification_title);
+            if (!ds.options_->notification_description.empty()) {
                 am_args.push_back("--es");
                 am_args.push_back("android.intent.extra.DESCRIPTION");
-                am_args.push_back(ds.notification_description);
+                am_args.push_back(ds.options_->notification_description);
             }
         }
-        if (options.is_remote_mode) {
+        if (ds.options_->is_remote_mode) {
             am_args.push_back("--es");
             am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
             am_args.push_back(SHA256_file_hash(ds.path_));
@@ -1936,30 +1940,77 @@
     }
 }
 
-int Dumpstate::ParseCommandlineOptions(int argc, char* argv[]) {
-    int ret = -1;  // success
+// TODO: Move away from system properties when we have options passed via binder calls.
+/* Sets runtime options from the system properties and then clears those properties. */
+static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
+    options->extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
+    if (!options->extra_options.empty()) {
+        // Framework uses a system property to override some command-line args.
+        // Currently, it contains the type of the requested bugreport.
+        if (options->extra_options == "bugreportplus") {
+            // Currently, the dumpstate binder is only used by Shell to update progress.
+            options->do_start_service = true;
+            options->do_progress_updates = true;
+            options->do_fb = false;
+        } else if (options->extra_options == "bugreportremote") {
+            options->do_vibrate = false;
+            options->is_remote_mode = true;
+            options->do_fb = false;
+        } else if (options->extra_options == "bugreportwear") {
+            options->do_start_service = true;
+            options->do_progress_updates = true;
+            options->do_zip_file = true;
+        } else if (options->extra_options == "bugreporttelephony") {
+            options->telephony_only = true;
+        } else if (options->extra_options == "bugreportwifi") {
+            options->wifi_only = true;
+            options->do_zip_file = true;
+        } else {
+            MYLOGE("Unknown extra option: %s\n", options->extra_options.c_str());
+        }
+        // Reset the property
+        android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
+    }
+
+    options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
+    if (!options->notification_title.empty()) {
+        // Reset the property
+        android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
+
+        options->extra_options = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+        if (!options->notification_description.empty()) {
+            // Reset the property
+            android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+        }
+        MYLOGD("notification (title:  %s, description: %s)\n", options->notification_title.c_str(),
+               options->notification_description.c_str());
+    }
+}
+
+Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
+    RunStatus status = RunStatus::OK;
     int c;
     while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
         switch (c) {
             // clang-format off
-            case 'd': options_.do_add_date = true;            break;
-            case 'z': options_.do_zip_file = true;            break;
-            case 'o': options_.use_outfile = optarg;          break;
-            case 's': options_.use_socket = true;             break;
-            case 'S': options_.use_control_socket = true;     break;
-            case 'v': options_.show_header_only = true;       break;
-            case 'q': options_.do_vibrate = false;            break;
-            case 'p': options_.do_fb = true;                  break;
-            case 'P': update_progress_ = true;                break;
-            case 'R': options_.is_remote_mode = true;         break;
-            case 'B': options_.do_broadcast = true;           break;
-            case 'V':                                         break;  // compatibility no-op
+            case 'd': do_add_date = true;            break;
+            case 'z': do_zip_file = true;            break;
+            case 'o': use_outfile = optarg;          break;
+            case 's': use_socket = true;             break;
+            case 'S': use_control_socket = true;     break;
+            case 'v': show_header_only = true;       break;
+            case 'q': do_vibrate = false;            break;
+            case 'p': do_fb = true;                  break;
+            case 'P': do_progress_updates = true;    break;
+            case 'R': is_remote_mode = true;         break;
+            case 'B': do_broadcast = true;           break;
+            case 'V':                                break;  // compatibility no-op
             case 'h':
-                ret = 0;
+                status = RunStatus::HELP;
                 break;
             default:
                 fprintf(stderr, "Invalid option: %c\n", c);
-                ret = 1;
+                status = RunStatus::INVALID_INPUT;
                 break;
                 // clang-format on
         }
@@ -1967,87 +2018,44 @@
 
     // TODO: use helper function to convert argv into a string
     for (int i = 0; i < argc; i++) {
-        args_ += argv[i];
+        args += argv[i];
         if (i < argc - 1) {
-            args_ += " ";
+            args += " ";
         }
     }
 
     // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
     optind = 1;
-    return ret;
+
+    SetOptionsFromProperties(this);
+    return status;
 }
 
-// TODO: Move away from system properties when we have binder.
-void Dumpstate::SetOptionsFromProperties() {
-    extra_options_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
-    if (!extra_options_.empty()) {
-        // Framework uses a system property to override some command-line args.
-        // Currently, it contains the type of the requested bugreport.
-        if (extra_options_ == "bugreportplus") {
-            // Currently, the dumpstate binder is only used by Shell to update progress.
-            options_.do_start_service = true;
-            update_progress_ = true;
-            options_.do_fb = false;
-        } else if (extra_options_ == "bugreportremote") {
-            options_.do_vibrate = false;
-            options_.is_remote_mode = true;
-            options_.do_fb = false;
-        } else if (extra_options_ == "bugreportwear") {
-            options_.do_start_service = true;
-            update_progress_ = true;
-            options_.do_zip_file = true;
-        } else if (extra_options_ == "bugreporttelephony") {
-            options_.telephony_only = true;
-        } else if (extra_options_ == "bugreportwifi") {
-            options_.wifi_only = true;
-            options_.do_zip_file = true;
-        } else {
-            MYLOGE("Unknown extra option: %s\n", extra_options_.c_str());
-        }
-        // Reset the property
-        android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
-    }
-
-    notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
-    if (!notification_title.empty()) {
-        // Reset the property
-        android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
-
-        notification_description = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
-        if (!notification_description.empty()) {
-            // Reset the property
-            android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
-        }
-        MYLOGD("notification (title:  %s, description: %s)\n", notification_title.c_str(),
-               notification_description.c_str());
-    }
-}
-
-bool Dumpstate::ValidateOptions() {
-    if ((options_.do_zip_file || options_.do_add_date || ds.update_progress_ ||
-         options_.do_broadcast) &&
-        options_.use_outfile.empty()) {
+bool Dumpstate::DumpOptions::ValidateOptions() const {
+    if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast)
+            && use_outfile.empty()) {
         return false;
     }
 
-    if (options_.use_control_socket && !options_.do_zip_file) {
+    if (use_control_socket && !do_zip_file) {
         return false;
     }
 
-    if (ds.update_progress_ && !options_.do_broadcast) {
+    if (do_progress_updates && !do_broadcast) {
         return false;
     }
 
-    if (options_.is_remote_mode && (ds.update_progress_ || !options_.do_broadcast ||
-                                    !options_.do_zip_file || !options_.do_add_date)) {
+    if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
         return false;
     }
     return true;
 }
 
-/* Main entry point for dumpstate. */
-int run_main(int argc, char* argv[]) {
+Dumpstate::RunStatus Dumpstate::RunWithOptions(std::unique_ptr<DumpOptions> options) {
+    if (!options->ValidateOptions()) {
+        return RunStatus::INVALID_INPUT;
+    }
+    options_ = std::move(options);
     /* set as high priority, and protect from OOM killer */
     setpriority(PRIO_PROCESS, 0, -20);
 
@@ -2064,52 +2072,42 @@
         }
     }
 
-    int status = ds.ParseCommandlineOptions(argc, argv);
-    if (status != -1) {
-        ShowUsageAndExit(status);
-    }
-    ds.SetOptionsFromProperties();
-    if (!ds.ValidateOptions()) {
-        ExitOnInvalidArgs();
+    if (version_ == VERSION_DEFAULT) {
+        version_ = VERSION_CURRENT;
     }
 
-    if (ds.version_ == VERSION_DEFAULT) {
-        ds.version_ = VERSION_CURRENT;
-    }
-
-    if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) {
+    if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
         MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
-               ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
+               version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
                VERSION_SPLIT_ANR.c_str());
-        exit(1);
+        return RunStatus::INVALID_INPUT;
     }
 
-    const Dumpstate::DumpOptions& options = ds.options_;
-    if (options.show_header_only) {
-        ds.PrintHeader();
-        exit(0);
+    if (options_->show_header_only) {
+        PrintHeader();
+        return RunStatus::OK;
     }
 
     // Redirect output if needed
-    bool is_redirecting = !options.use_socket && !options.use_outfile.empty();
+    bool is_redirecting = !options_->use_socket && !options_->use_outfile.empty();
 
     // TODO: temporarily set progress until it's part of the Dumpstate constructor
-    std::string stats_path = is_redirecting
-                                 ? android::base::StringPrintf("%s/dumpstate-stats.txt",
-                                                               dirname(options.use_outfile.c_str()))
-                                 : "";
-    ds.progress_.reset(new Progress(stats_path));
+    std::string stats_path =
+        is_redirecting ? android::base::StringPrintf("%s/dumpstate-stats.txt",
+                                                     dirname(options_->use_outfile.c_str()))
+                       : "";
+    progress_.reset(new Progress(stats_path));
 
     /* gets the sequential id */
     uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
-    ds.id_ = ++last_id;
+    id_ = ++last_id;
     android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
 
     MYLOGI("begin\n");
 
     register_sig_handler();
 
-    if (options.do_start_service) {
+    if (options_->do_start_service) {
         MYLOGI("Starting 'dumpstate' service\n");
         android::status_t ret;
         if ((ret = android::os::DumpstateService::Start()) != android::OK) {
@@ -2121,43 +2119,43 @@
         MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
     }
 
-    MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", ds.id_, ds.args_.c_str(),
-           ds.extra_options_.c_str());
+    MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
+           options_->extra_options.c_str());
 
-    MYLOGI("bugreport format version: %s\n", ds.version_.c_str());
+    MYLOGI("bugreport format version: %s\n", version_.c_str());
 
-    ds.do_early_screenshot_ = ds.update_progress_;
+    do_early_screenshot_ = options_->do_progress_updates;
 
     // If we are going to use a socket, do it as early as possible
     // to avoid timeouts from bugreport.
-    if (options.use_socket) {
+    if (options_->use_socket) {
         redirect_to_socket(stdout, "dumpstate");
     }
 
-    if (options.use_control_socket) {
+    if (options_->use_control_socket) {
         MYLOGD("Opening control socket\n");
-        ds.control_socket_fd_ = open_socket("dumpstate");
-        ds.update_progress_ = 1;
+        control_socket_fd_ = open_socket("dumpstate");
+        options_->do_progress_updates = 1;
     }
 
     if (is_redirecting) {
         PrepareToWriteToFile();
 
-        if (ds.update_progress_) {
-            if (options.do_broadcast) {
+        if (options_->do_progress_updates) {
+            if (options_->do_broadcast) {
                 // clang-format off
                 std::vector<std::string> am_args = {
                      "--receiver-permission", "android.permission.DUMP",
-                     "--es", "android.intent.extra.NAME", ds.name_,
-                     "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
-                     "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
-                     "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
+                     "--es", "android.intent.extra.NAME", name_,
+                     "--ei", "android.intent.extra.ID", std::to_string(id_),
+                     "--ei", "android.intent.extra.PID", std::to_string(pid_),
+                     "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
                 };
                 // clang-format on
                 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
             }
-            if (options.use_control_socket) {
-                dprintf(ds.control_socket_fd_, "BEGIN:%s\n", ds.path_.c_str());
+            if (options_->use_control_socket) {
+                dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
             }
         }
     }
@@ -2169,23 +2167,23 @@
         fclose(cmdline);
     }
 
-    if (options.do_vibrate) {
+    if (options_->do_vibrate) {
         Vibrate(150);
     }
 
-    if (options.do_fb && ds.do_early_screenshot_) {
-        if (ds.screenshot_path_.empty()) {
+    if (options_->do_fb && do_early_screenshot_) {
+        if (screenshot_path_.empty()) {
             // should not have happened
             MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
         } else {
             MYLOGI("taking early screenshot\n");
-            ds.TakeScreenshot();
+            TakeScreenshot();
         }
     }
 
-    if (options.do_zip_file && ds.zip_file != nullptr) {
-        if (chown(ds.path_.c_str(), AID_SHELL, AID_SHELL)) {
-            MYLOGE("Unable to change ownership of zip file %s: %s\n", ds.path_.c_str(),
+    if (options_->do_zip_file && zip_file != nullptr) {
+        if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
+            MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
                    strerror(errno));
         }
     }
@@ -2194,19 +2192,19 @@
     int dup_stderr_fd;
     if (is_redirecting) {
         TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
-        redirect_to_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
-        if (chown(ds.log_path_.c_str(), AID_SHELL, AID_SHELL)) {
-            MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
-                   ds.log_path_.c_str(), strerror(errno));
+        redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()));
+        if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
+            MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
+                   strerror(errno));
         }
         TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
         /* TODO: rather than generating a text file now and zipping it later,
            it would be more efficient to redirect stdout to the zip entry
            directly, but the libziparchive doesn't support that option yet. */
-        redirect_to_file(stdout, const_cast<char*>(ds.tmp_path_.c_str()));
-        if (chown(ds.tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
+        redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()));
+        if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
             MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
-                   ds.tmp_path_.c_str(), strerror(errno));
+                   tmp_path_.c_str(), strerror(errno));
         }
     }
 
@@ -2216,18 +2214,18 @@
     // NOTE: there should be no stdout output until now, otherwise it would break the header.
     // In particular, DurationReport objects should be created passing 'title, NULL', so their
     // duration is logged into MYLOG instead.
-    ds.PrintHeader();
+    PrintHeader();
 
-    if (options.telephony_only) {
+    if (options_->telephony_only) {
         DumpstateTelephonyOnly();
-        ds.DumpstateBoard();
-    } else if (options.wifi_only) {
+        DumpstateBoard();
+    } else if (options_->wifi_only) {
         DumpstateWifiOnly();
     } else {
         // Dump state for the default case. This also drops root.
         if (!DumpstateDefault()) {
             // Something went wrong.
-            return -1;
+            return RunStatus::ERROR;
         }
     }
 
@@ -2237,12 +2235,12 @@
     }
 
     /* rename or zip the (now complete) .tmp file to its final location */
-    if (!options.use_outfile.empty()) {
+    if (!options_->use_outfile.empty()) {
         FinalizeFile();
     }
 
     /* vibrate a few but shortly times to let user know it's finished */
-    if (options.do_vibrate) {
+    if (options_->do_vibrate) {
         for (int i = 0; i < 3; i++) {
             Vibrate(75);
             usleep((75 + 50) * 1000);
@@ -2250,26 +2248,51 @@
     }
 
     /* tell activity manager we're done */
-    if (options.do_broadcast) {
+    if (options_->do_broadcast) {
         SendBugreportFinishedBroadcast();
     }
 
-    MYLOGD("Final progress: %d/%d (estimated %d)\n", ds.progress_->Get(), ds.progress_->GetMax(),
-           ds.progress_->GetInitialMax());
-    ds.progress_->Save();
-    MYLOGI("done (id %d)\n", ds.id_);
+    MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
+           progress_->GetInitialMax());
+    progress_->Save();
+    MYLOGI("done (id %d)\n", id_);
 
     if (is_redirecting) {
         TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
     }
 
-    if (options.use_control_socket && ds.control_socket_fd_ != -1) {
+    if (options_->use_control_socket && control_socket_fd_ != -1) {
         MYLOGD("Closing control socket\n");
-        close(ds.control_socket_fd_);
+        close(control_socket_fd_);
     }
 
-    ds.tombstone_data_.clear();
-    ds.anr_data_.clear();
+    tombstone_data_.clear();
+    anr_data_.clear();
 
+    return RunStatus::OK;
+}
+
+/* Main entry point for dumpstate. */
+int run_main(int argc, char* argv[]) {
+    std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
+    Dumpstate::RunStatus status = options->Initialize(argc, argv);
+    if (status == Dumpstate::RunStatus::OK) {
+        status = ds.RunWithOptions(std::move(options));
+    }
+
+    switch (status) {
+        case Dumpstate::RunStatus::OK:
+            return 0;
+            break;
+        case Dumpstate::RunStatus::HELP:
+            ShowUsageAndExit(0 /* exit code */);
+            break;
+        case Dumpstate::RunStatus::INVALID_INPUT:
+            ExitOnInvalidArgs();
+            break;
+        case Dumpstate::RunStatus::ERROR:
+            exit(-1);
+            break;
+    }
     return 0;
 }
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 389cc2e..c2f7f6a 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -183,6 +183,8 @@
     friend class DumpstateTest;
 
   public:
+    enum RunStatus { OK, HELP, INVALID_INPUT, ERROR };
+
     static android::os::dumpstate::CommandOptions DEFAULT_DUMPSYS;
 
     static Dumpstate& GetInstance();
@@ -290,22 +292,12 @@
     /* Returns true if the current version supports priority dump feature. */
     bool CurrentVersionSupportsPriorityDumps() const;
 
-    // TODO: revisit the return values later.
-    /*
-     * Parses commandline arguments and sets runtime options accordingly.
-     *
-     * Returns 0 or positive number if the caller should exit with returned value as
-     * exit code, or returns -1 if caller should proceed with execution.
-     */
-    int ParseCommandlineOptions(int argc, char* argv[]);
+    struct DumpOptions;
 
-    /* Sets runtime options from the system properties. */
-    void SetOptionsFromProperties();
+    /* Main entry point for running a complete bugreport. Takes ownership of options. */
+    RunStatus RunWithOptions(std::unique_ptr<DumpOptions> options);
 
-    /* Returns true if the options set so far are consistent. */
-    bool ValidateOptions();
-
-    // TODO: add update_progress_ & other options from DumpState.
+    // TODO: add other options from DumpState.
     /*
      * Structure to hold options that determine the behavior of dumpstate.
      */
@@ -322,7 +314,22 @@
         bool do_start_service = false;
         bool telephony_only = false;
         bool wifi_only = false;
+        // Whether progress updates should be published.
+        bool do_progress_updates = false;
         std::string use_outfile;
+        // Extra options passed as system property.
+        std::string extra_options;
+        // Command-line arguments as string
+        std::string args;
+        // Notification title and description
+        std::string notification_title;
+        std::string notification_description;
+
+        /* Initializes options from commandline arguments and system properties. */
+        RunStatus Initialize(int argc, char* argv[]);
+
+        /* Returns true if the options set so far are consistent. */
+        bool ValidateOptions() const;
     };
 
     // TODO: initialize fields on constructor
@@ -333,10 +340,7 @@
     pid_t pid_;
 
     // Runtime options.
-    DumpOptions options_;
-
-    // Whether progress updates should be published.
-    bool update_progress_ = false;
+    std::unique_ptr<DumpOptions> options_;
 
     // How frequently the progess should be updated;the listener will only be notificated when the
     // delta from the previous update is more than the threshold.
@@ -356,12 +360,6 @@
     // Bugreport format version;
     std::string version_ = VERSION_CURRENT;
 
-    // Command-line arguments as string
-    std::string args_;
-
-    // Extra options passed as system property.
-    std::string extra_options_;
-
     // Full path of the directory where the bugreport files will be written.
     std::string bugreport_dir_;
 
@@ -398,10 +396,6 @@
     std::string listener_name_;
     bool report_section_;
 
-    // Notification title and description
-    std::string notification_title;
-    std::string notification_description;
-
     // List of open tombstone dump files.
     std::vector<DumpData> tombstone_data_;
 
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index c57535a..b675c51 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -137,6 +137,175 @@
     }
 };
 
+class DumpOptionsTest : public Test {
+  public:
+    virtual ~DumpOptionsTest() {
+    }
+    virtual void SetUp() {
+        options_ = Dumpstate::DumpOptions();
+    }
+
+    Dumpstate::DumpOptions options_;
+};
+
+TEST_F(DumpOptionsTest, InitializeNone) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate")
+    };
+    // clang-format on
+
+    Dumpstate::DumpOptions options;
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_FALSE(options_.do_add_date);
+    EXPECT_FALSE(options_.do_zip_file);
+    EXPECT_EQ("", options_.use_outfile);
+    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.do_fb);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.do_broadcast);
+}
+
+TEST_F(DumpOptionsTest, InitializePartial1) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-z"),
+        const_cast<char*>("-o abc"),
+        const_cast<char*>("-s"),
+        const_cast<char*>("-S"),
+
+    };
+    // clang-format on
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.do_add_date);
+    EXPECT_TRUE(options_.do_zip_file);
+    // TODO: Maybe we should trim the filename
+    EXPECT_EQ(" abc", std::string(options_.use_outfile));
+    EXPECT_TRUE(options_.use_socket);
+    EXPECT_TRUE(options_.use_control_socket);
+
+    // Other options retain default values
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.do_fb);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.do_broadcast);
+}
+
+TEST_F(DumpOptionsTest, InitializePartial2) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        const_cast<char*>("-v"),
+        const_cast<char*>("-q"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-P"),
+        const_cast<char*>("-R"),
+        const_cast<char*>("-B"),
+    };
+    // clang-format on
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_vibrate);
+    EXPECT_TRUE(options_.do_fb);
+    EXPECT_TRUE(options_.do_progress_updates);
+    EXPECT_TRUE(options_.is_remote_mode);
+    EXPECT_TRUE(options_.do_broadcast);
+
+    // Other options retain default values
+    EXPECT_FALSE(options_.do_add_date);
+    EXPECT_FALSE(options_.do_zip_file);
+    EXPECT_EQ("", options_.use_outfile);
+    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.use_control_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeHelp) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        const_cast<char*>("-h")
+    };
+    // clang-format on
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    // -h is for help.
+    EXPECT_EQ(status, Dumpstate::RunStatus::HELP);
+}
+
+TEST_F(DumpOptionsTest, InitializeUnknown) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        const_cast<char*>("-u")  // unknown flag
+    };
+    // clang-format on
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    // -u is unknown.
+    EXPECT_EQ(status, Dumpstate::RunStatus::INVALID_INPUT);
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) {
+    options_.do_zip_file = true;
+    EXPECT_FALSE(options_.ValidateOptions());
+    options_.use_outfile = "a/b/c";
+    EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
+    options_.do_broadcast = true;
+    EXPECT_FALSE(options_.ValidateOptions());
+    options_.use_outfile = "a/b/c";
+    EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsNeedZipfile) {
+    options_.use_control_socket = true;
+    EXPECT_FALSE(options_.ValidateOptions());
+
+    options_.do_zip_file = true;
+    options_.use_outfile = "a/b/c";  // do_zip_file needs outfile
+    EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
+    options_.do_progress_updates = true;
+    options_.use_outfile = "a/b/c";  // do_progress_updates needs outfile
+    EXPECT_FALSE(options_.ValidateOptions());
+
+    options_.do_broadcast = true;
+    EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) {
+    options_.is_remote_mode = true;
+    EXPECT_FALSE(options_.ValidateOptions());
+
+    options_.do_broadcast = true;
+    options_.do_zip_file = true;
+    options_.do_add_date = true;
+    options_.use_outfile = "a/b/c";  // do_broadcast needs outfile
+    EXPECT_TRUE(options_.ValidateOptions());
+}
+
 class DumpstateTest : public DumpstateBaseTest {
   public:
     void SetUp() {
@@ -144,9 +313,8 @@
         SetDryRun(false);
         SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)"));
         ds.progress_.reset(new Progress());
-        ds.update_progress_ = false;
         ds.update_progress_threshold_ = 0;
-        ds.options_ = Dumpstate::DumpOptions();
+        ds.options_.reset(new Dumpstate::DumpOptions());
     }
 
     // Runs a command and capture `stdout` and `stderr`.
@@ -171,7 +339,7 @@
     }
 
     void SetProgress(long progress, long initial_max, long threshold = 0) {
-        ds.update_progress_ = true;
+        ds.options_->do_progress_updates = true;
         ds.update_progress_threshold_ = threshold;
         ds.last_updated_progress_ = 0;
         ds.progress_.reset(new Progress(initial_max, progress, 1.2));
@@ -204,157 +372,6 @@
     Dumpstate& ds = Dumpstate::GetInstance();
 };
 
-TEST_F(DumpstateTest, ParseCommandlineOptionsNone) {
-    // clang-format off
-    char* argv[] = {
-        const_cast<char*>("dumpstate")
-    };
-    // clang-format on
-
-    int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
-    EXPECT_EQ(-1, ret);
-    EXPECT_FALSE(ds.options_.do_add_date);
-    EXPECT_FALSE(ds.options_.do_zip_file);
-    EXPECT_EQ("", ds.options_.use_outfile);
-    EXPECT_FALSE(ds.options_.use_socket);
-    EXPECT_FALSE(ds.options_.use_control_socket);
-    EXPECT_FALSE(ds.options_.show_header_only);
-    EXPECT_TRUE(ds.options_.do_vibrate);
-    EXPECT_FALSE(ds.options_.do_fb);
-    EXPECT_FALSE(ds.update_progress_);
-    EXPECT_FALSE(ds.options_.is_remote_mode);
-    EXPECT_FALSE(ds.options_.do_broadcast);
-}
-
-TEST_F(DumpstateTest, ParseCommandlineOptionsPartial1) {
-    // clang-format off
-    char* argv[] = {
-        const_cast<char*>("dumpstate"),
-        const_cast<char*>("-d"),
-        const_cast<char*>("-z"),
-        const_cast<char*>("-o abc"),
-        const_cast<char*>("-s"),
-        const_cast<char*>("-S"),
-
-    };
-    // clang-format on
-    int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
-    EXPECT_EQ(-1, ret);
-    EXPECT_TRUE(ds.options_.do_add_date);
-    EXPECT_TRUE(ds.options_.do_zip_file);
-    // TODO: Maybe we should trim the filename
-    EXPECT_EQ(" abc", std::string(ds.options_.use_outfile));
-    EXPECT_TRUE(ds.options_.use_socket);
-    EXPECT_TRUE(ds.options_.use_control_socket);
-
-    // Other options retain default values
-    EXPECT_FALSE(ds.options_.show_header_only);
-    EXPECT_TRUE(ds.options_.do_vibrate);
-    EXPECT_FALSE(ds.options_.do_fb);
-    EXPECT_FALSE(ds.update_progress_);
-    EXPECT_FALSE(ds.options_.is_remote_mode);
-    EXPECT_FALSE(ds.options_.do_broadcast);
-}
-
-TEST_F(DumpstateTest, ParseCommandlineOptionsPartial2) {
-    // clang-format off
-    char* argv[] = {
-        const_cast<char*>("dumpstate"),
-        const_cast<char*>("-v"),
-        const_cast<char*>("-q"),
-        const_cast<char*>("-p"),
-        const_cast<char*>("-P"),
-        const_cast<char*>("-R"),
-        const_cast<char*>("-B"),
-    };
-    // clang-format on
-    int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
-    EXPECT_EQ(-1, ret);
-    EXPECT_TRUE(ds.options_.show_header_only);
-    EXPECT_FALSE(ds.options_.do_vibrate);
-    EXPECT_TRUE(ds.options_.do_fb);
-    EXPECT_TRUE(ds.update_progress_);
-    EXPECT_TRUE(ds.options_.is_remote_mode);
-    EXPECT_TRUE(ds.options_.do_broadcast);
-
-    // Other options retain default values
-    EXPECT_FALSE(ds.options_.do_add_date);
-    EXPECT_FALSE(ds.options_.do_zip_file);
-    EXPECT_EQ("", ds.options_.use_outfile);
-    EXPECT_FALSE(ds.options_.use_socket);
-    EXPECT_FALSE(ds.options_.use_control_socket);
-}
-
-TEST_F(DumpstateTest, ParseCommandlineOptionsHelp) {
-    // clang-format off
-    char* argv[] = {
-        const_cast<char*>("dumpstate"),
-        const_cast<char*>("-h")
-    };
-    // clang-format on
-    int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
-
-    // -h is for help. Caller exit with code = 0 after printing usage, so expect return = 0.
-    EXPECT_EQ(0, ret);
-}
-
-TEST_F(DumpstateTest, ParseCommandlineOptionsUnknown) {
-    // clang-format off
-    char* argv[] = {
-        const_cast<char*>("dumpstate"),
-        const_cast<char*>("-u")  // unknown flag
-    };
-    // clang-format on
-    int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
-
-    // -u is unknown. Caller exit with code = 1 to show execution failure, after printing usage,
-    // so expect return = 1.
-    EXPECT_EQ(1, ret);
-}
-
-TEST_F(DumpstateTest, ValidateOptionsNeedOutfile1) {
-    ds.options_.do_zip_file = true;
-    EXPECT_FALSE(ds.ValidateOptions());
-    ds.options_.use_outfile = "a/b/c";
-    EXPECT_TRUE(ds.ValidateOptions());
-}
-
-TEST_F(DumpstateTest, ValidateOptionsNeedOutfile2) {
-    ds.options_.do_broadcast = true;
-    EXPECT_FALSE(ds.ValidateOptions());
-    ds.options_.use_outfile = "a/b/c";
-    EXPECT_TRUE(ds.ValidateOptions());
-}
-
-TEST_F(DumpstateTest, ValidateOptionsNeedZipfile) {
-    ds.options_.use_control_socket = true;
-    EXPECT_FALSE(ds.ValidateOptions());
-
-    ds.options_.do_zip_file = true;
-    ds.options_.use_outfile = "a/b/c";  // do_zip_file needs outfile
-    EXPECT_TRUE(ds.ValidateOptions());
-}
-
-TEST_F(DumpstateTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
-    ds.update_progress_ = true;
-    ds.options_.use_outfile = "a/b/c";  // update_progress_ needs outfile
-    EXPECT_FALSE(ds.ValidateOptions());
-
-    ds.options_.do_broadcast = true;
-    EXPECT_TRUE(ds.ValidateOptions());
-}
-
-TEST_F(DumpstateTest, ValidateOptionsRemoteMode) {
-    ds.options_.is_remote_mode = true;
-    EXPECT_FALSE(ds.ValidateOptions());
-
-    ds.options_.do_broadcast = true;
-    ds.options_.do_zip_file = true;
-    ds.options_.do_add_date = true;
-    ds.options_.use_outfile = "a/b/c";  // do_broadcast needs outfile
-    EXPECT_TRUE(ds.ValidateOptions());
-}
-
 TEST_F(DumpstateTest, RunCommandNoArgs) {
     EXPECT_EQ(-1, RunCommand("", {}));
 }
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 77f09b7..4ad5c4b 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -916,7 +916,7 @@
     bool max_changed = progress_->Inc(delta_sec);
 
     // ...but only notifiy listeners when necessary.
-    if (!update_progress_) return;
+    if (!options_->do_progress_updates) return;
 
     int progress = progress_->Get();
     int max = progress_->GetMax();
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 9d0d8ba..2e9701f 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -14,6 +14,7 @@
         "CacheItem.cpp",
         "CacheTracker.cpp",
         "InstalldNativeService.cpp",
+        "QuotaUtils.cpp",
         "dexopt.cpp",
         "globals.cpp",
         "utils.cpp",
@@ -33,6 +34,21 @@
         "libutils",
     ],
 
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
+
     clang: true,
 
     tidy: true,
@@ -59,6 +75,26 @@
     aidl: {
         export_aidl_headers: true,
     },
+
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
+}
+
+cc_library_headers {
+    name: "libinstalld_headers",
+    export_include_dirs: ["."],
 }
 
 //
@@ -73,6 +109,21 @@
     static_libs: ["libdiskusage"],
 
     init_rc: ["installd.rc"],
+
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
 }
 
 // OTA chroot tool
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index a7242c3..8b868fb 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -19,13 +19,13 @@
 #include "CacheTracker.h"
 
 #include <fts.h>
-#include <sys/quota.h>
 #include <sys/xattr.h>
 #include <utils/Trace.h>
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 
+#include "QuotaUtils.h"
 #include "utils.h"
 
 using android::base::StringPrintf;
@@ -33,9 +33,13 @@
 namespace android {
 namespace installd {
 
-CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice) :
-        cacheUsed(0), cacheQuota(0), mUserId(userId), mAppId(appId), mQuotaDevice(quotaDevice),
-        mItemsLoaded(false) {
+CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& uuid)
+      : cacheUsed(0),
+        cacheQuota(0),
+        mUserId(userId),
+        mAppId(appId),
+        mItemsLoaded(false),
+        mUuid(uuid) {
 }
 
 CacheTracker::~CacheTracker() {
@@ -72,26 +76,18 @@
 bool CacheTracker::loadQuotaStats() {
     int cacheGid = multiuser_get_cache_gid(mUserId, mAppId);
     int extCacheGid = multiuser_get_ext_cache_gid(mUserId, mAppId);
-    if (!mQuotaDevice.empty() && cacheGid != -1 && extCacheGid != -1) {
-        struct dqblk dq;
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
-            }
-            return false;
+    if (IsQuotaSupported(mUuid) && cacheGid != -1 && extCacheGid != -1) {
+        int64_t space;
+        if ((space = GetOccupiedSpaceForGid(mUuid, cacheGid)) != -1) {
+            cacheUsed += space;
         } else {
-            cacheUsed += dq.dqb_curspace;
+            return false;
         }
 
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), extCacheGid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
-            }
-            return false;
+        if ((space = GetOccupiedSpaceForGid(mUuid, extCacheGid)) != -1) {
+            cacheUsed += space;
         } else {
-            cacheUsed += dq.dqb_curspace;
+            return false;
         }
         return true;
     } else {
diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h
index 44359b4..b0527e7 100644
--- a/cmds/installd/CacheTracker.h
+++ b/cmds/installd/CacheTracker.h
@@ -39,7 +39,7 @@
  */
 class CacheTracker {
 public:
-    CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice);
+    CacheTracker(userid_t userId, appid_t appId, const std::string& uuid);
     ~CacheTracker();
 
     std::string toString();
@@ -61,8 +61,8 @@
 private:
     userid_t mUserId;
     appid_t mAppId;
-    std::string mQuotaDevice;
     bool mItemsLoaded;
+    const std::string& mUuid;
 
     std::vector<std::string> mDataPaths;
 
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index e4990b0..81055d8 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -31,7 +31,6 @@
 #include <sys/file.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
-#include <sys/quota.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
@@ -64,6 +63,7 @@
 
 #include "CacheTracker.h"
 #include "MatchExtensionGen.h"
+#include "QuotaUtils.h"
 
 #ifndef LOG_TAG
 #define LOG_TAG "installd"
@@ -77,7 +77,6 @@
 
 static constexpr const char* kCpPath = "/system/bin/cp";
 static constexpr const char* kXattrDefault = "user.default";
-static constexpr const char* kPropHasReserved = "vold.has_reserved";
 
 static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
 
@@ -258,11 +257,6 @@
         for (const auto& n : mStorageMounts) {
             out << "    " << n.first << " = " << n.second << endl;
         }
-
-        out << endl << "Quota reverse mounts:" << endl;
-        for (const auto& n : mQuotaReverseMounts) {
-            out << "    " << n.first << " = " << n.second << endl;
-        }
     }
 
     {
@@ -343,55 +337,6 @@
     return 0;
 }
 
-/**
- * Ensure that we have a hard-limit quota to protect against abusive apps;
- * they should never use more than 90% of blocks or 50% of inodes.
- */
-static int prepare_app_quota(const std::unique_ptr<std::string>& uuid ATTRIBUTE_UNUSED,
-        const std::string& device, uid_t uid) {
-    // Skip when reserved blocks are protecting us against abusive apps
-    if (android::base::GetBoolProperty(kPropHasReserved, false)) return 0;
-    // Skip when device no quotas present
-    if (device.empty()) return 0;
-
-    struct dqblk dq;
-    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
-            reinterpret_cast<char*>(&dq)) != 0) {
-        PLOG(WARNING) << "Failed to find quota for " << uid;
-        return -1;
-    }
-
-#if APPLY_HARD_QUOTAS
-    if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) {
-        auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
-        struct statvfs stat;
-        if (statvfs(path.c_str(), &stat) != 0) {
-            PLOG(WARNING) << "Failed to statvfs " << path;
-            return -1;
-        }
-
-        dq.dqb_valid = QIF_LIMITS;
-        dq.dqb_bhardlimit =
-            (((static_cast<uint64_t>(stat.f_blocks) * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
-        dq.dqb_ihardlimit = (stat.f_files / 2);
-        if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            PLOG(WARNING) << "Failed to set hard quota for " << uid;
-            return -1;
-        } else {
-            LOG(DEBUG) << "Applied hard quotas for " << uid;
-            return 0;
-        }
-    } else {
-        // Hard quota already set; assume it's reasonable
-        return 0;
-    }
-#else
-    // Hard quotas disabled
-    return 0;
-#endif
-}
-
 static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
     if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
         return true;
@@ -506,10 +451,6 @@
             return error("Failed to restorecon " + path);
         }
 
-        if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) {
-            return error("Failed to set hard quota " + path);
-        }
-
         if (!prepare_app_profile_dir(packageName, appId, userId)) {
             return error("Failed to prepare profiles for " + packageName);
         }
@@ -616,6 +557,10 @@
             // No code cache on shared storage
         } else {
             // Clear everything on shared storage
+            path = StringPrintf("%s/Android/sandbox/%s", extPath.c_str(), pkgname);
+            if (delete_dir_contents(path, true) != 0) {
+                res = error("Failed to delete contents of " + path);
+            }
             path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
             if (delete_dir_contents(path, true) != 0) {
                 res = error("Failed to delete contents of " + path);
@@ -699,6 +644,10 @@
         }
 
         auto extPath = findDataMediaPath(uuid, userId);
+        path = StringPrintf("%s/Android/sandbox/%s", extPath.c_str(), pkgname);
+        if (delete_dir_contents_and_dir(path, true) != 0) {
+            res = error("Failed to delete " + path);
+        }
         path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
         if (delete_dir_contents_and_dir(path, true) != 0) {
             res = error("Failed to delete " + path);
@@ -988,13 +937,6 @@
         }
     }
 
-    // Data under /data/media doesn't have an app, but we still want
-    // to limit it to prevent abuse.
-    if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid),
-            multiuser_get_uid(userId, AID_MEDIA_RW))) {
-        return error("Failed to set hard quota for media_rw");
-    }
-
     return ok();
 }
 
@@ -1041,9 +983,9 @@
     CHECK_ARGUMENT_UUID(uuid);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     auto data_path = create_data_path(uuid_);
-    auto device = findQuotaDeviceForUuid(uuid);
     auto noop = (flags & FLAG_FREE_CACHE_NOOP);
 
     int64_t free = data_disk_free(data_path);
@@ -1090,7 +1032,7 @@
                         search->second->addDataPath(p->fts_path);
                     } else {
                         auto tracker = std::shared_ptr<CacheTracker>(new CacheTracker(
-                                multiuser_get_user_id(uid), multiuser_get_app_id(uid), device));
+                                multiuser_get_user_id(uid), multiuser_get_app_id(uid), uuidString));
                         tracker->addDataPath(p->fts_path);
                         {
                             std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
@@ -1255,53 +1197,26 @@
 }
 #endif
 
-static void collectQuotaStats(const std::string& device, int32_t userId,
+static void collectQuotaStats(const std::string& uuid, int32_t userId,
         int32_t appId, struct stats* stats, struct stats* extStats) {
-    if (device.empty()) return;
-
-    struct dqblk dq;
-
+    int64_t space;
     if (stats != nullptr) {
         uid_t uid = multiuser_get_uid(userId, appId);
-        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
-            }
-        } else {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
-            stats->dataSize += dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
+            stats->dataSize += space;
         }
 
         int cacheGid = multiuser_get_cache_gid(userId, appId);
         if (cacheGid != -1) {
-            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), cacheGid,
-                    reinterpret_cast<char*>(&dq)) != 0) {
-                if (errno != ESRCH) {
-                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << cacheGid;
-                }
-            } else {
-#if MEASURE_DEBUG
-                LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
-#endif
-                stats->cacheSize += dq.dqb_curspace;
+            if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+                stats->cacheSize += space;
             }
         }
 
         int sharedGid = multiuser_get_shared_gid(0, appId);
         if (sharedGid != -1) {
-            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid,
-                    reinterpret_cast<char*>(&dq)) != 0) {
-                if (errno != ESRCH) {
-                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << sharedGid;
-                }
-            } else {
-#if MEASURE_DEBUG
-                LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
-#endif
-                stats->codeSize += dq.dqb_curspace;
+            if ((space = GetOccupiedSpaceForGid(uuid, sharedGid)) != -1) {
+                stats->codeSize += space;
             }
         }
     }
@@ -1309,32 +1224,16 @@
     if (extStats != nullptr) {
         int extGid = multiuser_get_ext_gid(userId, appId);
         if (extGid != -1) {
-            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid,
-                    reinterpret_cast<char*>(&dq)) != 0) {
-                if (errno != ESRCH) {
-                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extGid;
-                }
-            } else {
-#if MEASURE_DEBUG
-                LOG(DEBUG) << "quotactl() for GID " << extGid << " " << dq.dqb_curspace;
-#endif
-                extStats->dataSize += dq.dqb_curspace;
+            if ((space = GetOccupiedSpaceForGid(uuid, extGid)) != -1) {
+                extStats->dataSize += space;
             }
         }
 
         int extCacheGid = multiuser_get_ext_cache_gid(userId, appId);
         if (extCacheGid != -1) {
-            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extCacheGid,
-                    reinterpret_cast<char*>(&dq)) != 0) {
-                if (errno != ESRCH) {
-                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extCacheGid;
-                }
-            } else {
-#if MEASURE_DEBUG
-                LOG(DEBUG) << "quotactl() for GID " << extCacheGid << " " << dq.dqb_curspace;
-#endif
-                extStats->dataSize += dq.dqb_curspace;
-                extStats->cacheSize += dq.dqb_curspace;
+            if ((space = GetOccupiedSpaceForGid(uuid, extCacheGid)) != -1) {
+                extStats->dataSize += space;
+                extStats->cacheSize += space;
             }
         }
     }
@@ -1498,10 +1397,10 @@
     memset(&stats, 0, sizeof(stats));
     memset(&extStats, 0, sizeof(extStats));
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
-    auto device = findQuotaDeviceForUuid(uuid);
-    if (device.empty()) {
+    if (!IsQuotaSupported(uuidString)) {
         flags &= ~FLAG_USE_QUOTA;
     }
 
@@ -1521,7 +1420,7 @@
         ATRACE_END();
 
         ATRACE_BEGIN("quota");
-        collectQuotaStats(device, userId, appId, &stats, &extStats);
+        collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
         ATRACE_END();
     } else {
         ATRACE_BEGIN("code");
@@ -1552,6 +1451,8 @@
             }
 
             ATRACE_BEGIN("external");
+            auto sandboxPath = create_data_media_package_path(uuid_, userId, "sandbox", pkgname);
+            calculate_tree_size(sandboxPath, &extStats.dataSize);
             auto extPath = create_data_media_package_path(uuid_, userId, "data", pkgname);
             collectManualStats(extPath, &extStats);
             auto mediaPath = create_data_media_package_path(uuid_, userId, "media", pkgname);
@@ -1604,27 +1505,19 @@
     memset(&stats, 0, sizeof(stats));
     memset(&extStats, 0, sizeof(extStats));
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
-    auto device = findQuotaDeviceForUuid(uuid);
-    if (device.empty()) {
+    if (!IsQuotaSupported(uuidString)) {
         flags &= ~FLAG_USE_QUOTA;
     }
 
     if (flags & FLAG_USE_QUOTA) {
-        struct dqblk dq;
+        int64_t space;
 
         ATRACE_BEGIN("obb");
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << AID_MEDIA_OBB;
-            }
-        } else {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
-#endif
-            extStats.codeSize += dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) {
+            extStats.codeSize += space;
         }
         ATRACE_END();
 
@@ -1650,16 +1543,8 @@
 
         ATRACE_BEGIN("external");
         uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
-        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
-            }
-        } else {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
-            extStats.dataSize += dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) {
+            extStats.dataSize += space;
         }
         ATRACE_END();
 
@@ -1676,7 +1561,7 @@
         int64_t dataSize = extStats.dataSize;
         for (auto appId : appIds) {
             if (appId >= AID_APP_START) {
-                collectQuotaStats(device, userId, appId, &stats, &extStats);
+                collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
 
 #if MEASURE_DEBUG
                 // Sleep to make sure we don't lose logs
@@ -1758,6 +1643,7 @@
     LOG(INFO) << "Measuring external " << userId;
 #endif
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
     int64_t totalSize = 0;
@@ -1767,58 +1653,33 @@
     int64_t appSize = 0;
     int64_t obbSize = 0;
 
-    auto device = findQuotaDeviceForUuid(uuid);
-    if (device.empty()) {
+    if (!IsQuotaSupported(uuidString)) {
         flags &= ~FLAG_USE_QUOTA;
     }
 
     if (flags & FLAG_USE_QUOTA) {
-        struct dqblk dq;
+        int64_t space;
 
         ATRACE_BEGIN("quota");
         uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
-        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
-            }
-        } else {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
-            totalSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) {
+            totalSize = space;
         }
 
         gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO);
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), audioGid,
-                reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << audioGid << " " << dq.dqb_curspace;
-#endif
-            audioSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, audioGid)) != -1) {
+            audioSize = space;
         }
         gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO);
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), videoGid,
-                reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << videoGid << " " << dq.dqb_curspace;
-#endif
-            videoSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, videoGid)) != -1) {
+            videoSize = space;
         }
         gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE);
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), imageGid,
-                reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << imageGid << " " << dq.dqb_curspace;
-#endif
-            imageSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, imageGid)) != -1) {
+            imageSize = space;
         }
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
-                reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
-#endif
-            obbSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) {
+            obbSize = space;
         }
         ATRACE_END();
 
@@ -1827,7 +1688,7 @@
         memset(&extStats, 0, sizeof(extStats));
         for (auto appId : appIds) {
             if (appId >= AID_APP_START) {
-                collectQuotaStats(device, userId, appId, nullptr, &extStats);
+                collectQuotaStats(uuidString, userId, appId, nullptr, &extStats);
             }
         }
         appSize = extStats.dataSize;
@@ -2615,7 +2476,12 @@
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
 
     mStorageMounts.clear();
-    mQuotaReverseMounts.clear();
+
+#if !BYPASS_QUOTA
+    if (!InvalidateQuotaMounts()) {
+        return error("Failed to read mounts");
+    }
+#endif
 
     std::ifstream in("/proc/mounts");
     if (!in.is_open()) {
@@ -2636,32 +2502,6 @@
             mStorageMounts[source] = target;
         }
 #endif
-
-#if !BYPASS_QUOTA
-        if (source.compare(0, 11, "/dev/block/") == 0) {
-            struct dqblk dq;
-            if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
-                    reinterpret_cast<char*>(&dq)) == 0) {
-                LOG(DEBUG) << "Found quota mount " << source << " at " << target;
-                mQuotaReverseMounts[target] = source;
-
-                // ext4 only enables DQUOT_USAGE_ENABLED by default, so we
-                // need to kick it again to enable DQUOT_LIMITS_ENABLED. We
-                // only need hard limits enabled when we're not being protected
-                // by reserved blocks.
-                if (!android::base::GetBoolProperty(kPropHasReserved, false)) {
-                    if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1,
-                            nullptr) != 0 && errno != EBUSY) {
-                        PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
-                    }
-                    if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1,
-                            nullptr) != 0 && errno != EBUSY) {
-                        PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
-                    }
-                }
-            }
-        }
-#endif
     }
     return ok();
 }
@@ -2679,16 +2519,10 @@
     return StringPrintf("%s/%u", resolved.c_str(), userid);
 }
 
-std::string InstalldNativeService::findQuotaDeviceForUuid(
-        const std::unique_ptr<std::string>& uuid) {
-    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
-    auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
-    return mQuotaReverseMounts[path];
-}
-
 binder::Status InstalldNativeService::isQuotaSupported(
-        const std::unique_ptr<std::string>& volumeUuid, bool* _aidl_return) {
-    *_aidl_return = !findQuotaDeviceForUuid(volumeUuid).empty();
+        const std::unique_ptr<std::string>& uuid, bool* _aidl_return) {
+    auto uuidString = uuid ? *uuid : "";
+    *_aidl_return = IsQuotaSupported(uuidString);
     return ok();
 }
 
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index cebd3f9..367f2c1 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -150,14 +150,11 @@
 
     /* Map of all storage mounts from source to target */
     std::unordered_map<std::string, std::string> mStorageMounts;
-    /* Map of all quota mounts from target to source */
-    std::unordered_map<std::string, std::string> mQuotaReverseMounts;
 
     /* Map from UID to cache quota size */
     std::unordered_map<uid_t, int64_t> mCacheQuotas;
 
     std::string findDataMediaPath(const std::unique_ptr<std::string>& uuid, userid_t userid);
-    std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
 };
 
 }  // namespace installd
diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS
index 50440f1..5d4f176 100644
--- a/cmds/installd/OWNERS
+++ b/cmds/installd/OWNERS
@@ -1,7 +1,8 @@
 set noparent
 
-calin@google.com
 agampe@google.com
+calin@google.com
 jsharkey@android.com
-toddke@google.com
+mathieuc@google.com
 ngeoffray@google.com
+toddke@google.com
diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp
new file mode 100644
index 0000000..b238dd3
--- /dev/null
+++ b/cmds/installd/QuotaUtils.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "QuotaUtils.h"
+
+#include <fstream>
+#include <unordered_map>
+
+#include <sys/quota.h>
+
+#include <android-base/logging.h>
+
+#include "utils.h"
+
+namespace android {
+namespace installd {
+
+namespace {
+
+std::recursive_mutex mMountsLock;
+
+/* Map of all quota mounts from target to source */
+std::unordered_map<std::string, std::string> mQuotaReverseMounts;
+
+std::string& FindQuotaDeviceForUuid(const std::string& uuid) {
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+    auto path = create_data_path(uuid.empty() ? nullptr : uuid.c_str());
+    return mQuotaReverseMounts[path];
+}
+
+} // namespace
+
+bool InvalidateQuotaMounts() {
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+
+    mQuotaReverseMounts.clear();
+
+    std::ifstream in("/proc/mounts");
+    if (!in.is_open()) {
+        return false;
+    }
+
+    std::string source;
+    std::string target;
+    std::string ignored;
+    while (!in.eof()) {
+        std::getline(in, source, ' ');
+        std::getline(in, target, ' ');
+        std::getline(in, ignored);
+
+        if (source.compare(0, 11, "/dev/block/") == 0) {
+            struct dqblk dq;
+            if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
+                    reinterpret_cast<char*>(&dq)) == 0) {
+                LOG(DEBUG) << "Found quota mount " << source << " at " << target;
+                mQuotaReverseMounts[target] = source;
+            }
+        }
+    }
+    return true;
+}
+
+bool IsQuotaSupported(const std::string& uuid) {
+    return !FindQuotaDeviceForUuid(uuid).empty();
+}
+
+int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid) {
+    const std::string device = FindQuotaDeviceForUuid(uuid);
+    if (device == "") {
+        return -1;
+    }
+    struct dqblk dq;
+    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+            reinterpret_cast<char*>(&dq)) != 0) {
+        if (errno != ESRCH) {
+            PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+        }
+        return -1;
+    } else {
+#if MEASURE_DEBUG
+        LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
+#endif
+        return dq.dqb_curspace;
+    }
+}
+
+int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) {
+    const std::string device = FindQuotaDeviceForUuid(uuid);
+    if (device == "") {
+        return -1;
+    }
+    struct dqblk dq;
+    if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), gid,
+            reinterpret_cast<char*>(&dq)) != 0) {
+        if (errno != ESRCH) {
+            PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << gid;
+        }
+        return -1;
+    } else {
+#if MEASURE_DEBUG
+        LOG(DEBUG) << "quotactl() for GID " << gid << " " << dq.dqb_curspace;
+#endif
+        return dq.dqb_curspace;
+    }
+
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/QuotaUtils.h b/cmds/installd/QuotaUtils.h
new file mode 100644
index 0000000..9ad170f
--- /dev/null
+++ b/cmds/installd/QuotaUtils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_QUOTA_UTILS_H_
+#define ANDROID_INSTALLD_QUOTA_UTILS_H_
+
+#include <memory>
+#include <string>
+
+namespace android {
+namespace installd {
+
+/* Clear and recompute the reverse mounts map */
+bool InvalidateQuotaMounts();
+
+/* Whether quota is supported in the device with the given uuid */
+bool IsQuotaSupported(const std::string& uuid);
+
+/* Get the current occupied space in bytes for a uid or -1 if fails */
+int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid);
+
+/* Get the current occupied space in bytes for a gid or -1 if fails */
+int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid);
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // ANDROID_INSTALLD_QUOTA_UTILS_H_
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 66dece7..aad9939 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -54,6 +54,8 @@
 #include "utils.h"
 
 using android::base::EndsWith;
+using android::base::GetBoolProperty;
+using android::base::GetProperty;
 using android::base::ReadFully;
 using android::base::StringPrintf;
 using android::base::WriteFully;
@@ -181,36 +183,11 @@
     return clear_current_profile(package_name, location, user, /*is_secondary_dex*/false);
 }
 
-static int split_count(const char *str)
-{
-  char *ctx;
-  int count = 0;
-  char buf[kPropertyValueMax];
-
-  strlcpy(buf, str, sizeof(buf));
-  char *pBuf = buf;
-
-  while(strtok_r(pBuf, " ", &ctx) != nullptr) {
-    count++;
-    pBuf = nullptr;
-  }
-
-  return count;
-}
-
-static int split(char *buf, const char **argv)
-{
-  char *ctx;
-  int count = 0;
-  char *tok;
-  char *pBuf = buf;
-
-  while((tok = strtok_r(pBuf, " ", &ctx)) != nullptr) {
-    argv[count++] = tok;
-    pBuf = nullptr;
-  }
-
-  return count;
+static std::vector<std::string> SplitBySpaces(const std::string& str) {
+    if (str.empty()) {
+        return {};
+    }
+    return android::base::Split(str, " ");
 }
 
 static const char* get_location_from_path(const char* path) {
@@ -224,341 +201,279 @@
     }
 }
 
-[[ noreturn ]]
-static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
-        const char* input_file_name, const char* output_file_name, int swap_fd,
-        const char* instruction_set, const char* compiler_filter,
-        bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
-        const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks,
-        bool generate_compact_dex, int dex_metadata_fd, const char* compilation_reason) {
-    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+// ExecVHelper prepares and holds pointers to parsed command line arguments so that no allocations
+// need to be performed between the fork and exec.
+class ExecVHelper {
+  public:
+    // Store a placeholder for the binary name.
+    ExecVHelper() : args_(1u, std::string()) {}
 
-    if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
-        LOG(ERROR) << "Instruction set '" << instruction_set << "' longer than max length of "
-                   << MAX_INSTRUCTION_SET_LEN;
-        exit(DexoptReturnCodes::kInstructionSetLength);
+    void PrepareArgs(const std::string& bin) {
+        CHECK(!args_.empty());
+        CHECK(args_[0].empty());
+        args_[0] = bin;
+        // Write char* into array.
+        for (const std::string& arg : args_) {
+            argv_.push_back(arg.c_str());
+        }
+        argv_.push_back(nullptr);  // Add null terminator.
     }
 
-    // Get the relative path to the input file.
-    const char* relative_input_file_name = get_location_from_path(input_file_name);
-
-    char dex2oat_Xms_flag[kPropertyValueMax];
-    bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, nullptr) > 0;
-
-    char dex2oat_Xmx_flag[kPropertyValueMax];
-    bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, nullptr) > 0;
-
-    char dex2oat_threads_buf[kPropertyValueMax];
-    bool have_dex2oat_threads_flag = get_property(post_bootcomplete
-                                                      ? "dalvik.vm.dex2oat-threads"
-                                                      : "dalvik.vm.boot-dex2oat-threads",
-                                                  dex2oat_threads_buf,
-                                                  nullptr) > 0;
-    char dex2oat_threads_arg[kPropertyValueMax + 2];
-    if (have_dex2oat_threads_flag) {
-        sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);
+    [[ noreturn ]]
+    void Exec(int exit_code) {
+        execv(argv_[0], (char * const *)&argv_[0]);
+        PLOG(ERROR) << "execv(" << argv_[0] << ") failed";
+        exit(exit_code);
     }
 
-    char dex2oat_isa_features_key[kPropertyKeyMax];
-    sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
-    char dex2oat_isa_features[kPropertyValueMax];
-    bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key,
-                                                  dex2oat_isa_features, nullptr) > 0;
-
-    char dex2oat_isa_variant_key[kPropertyKeyMax];
-    sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
-    char dex2oat_isa_variant[kPropertyValueMax];
-    bool have_dex2oat_isa_variant = get_property(dex2oat_isa_variant_key,
-                                                 dex2oat_isa_variant, nullptr) > 0;
-
-    const char *dex2oat_norelocation = "-Xnorelocate";
-    bool have_dex2oat_relocation_skip_flag = false;
-
-    char dex2oat_flags[kPropertyValueMax];
-    int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags",
-                                 dex2oat_flags, nullptr) <= 0 ? 0 : split_count(dex2oat_flags);
-    ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
-
-    // If we are booting without the real /data, don't spend time compiling.
-    char vold_decrypt[kPropertyValueMax];
-    bool have_vold_decrypt = get_property("vold.decrypt", vold_decrypt, "") > 0;
-    bool skip_compilation = (have_vold_decrypt &&
-                             (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||
-                             (strcmp(vold_decrypt, "1") == 0)));
-
-    bool generate_debug_info = property_get_bool("debug.generate-debug-info", false);
-
-    char app_image_format[kPropertyValueMax];
-    char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
-    bool have_app_image_format =
-            image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, nullptr) > 0;
-    if (have_app_image_format) {
-        sprintf(image_format_arg, "--image-format=%s", app_image_format);
-    }
-
-    char dex2oat_large_app_threshold[kPropertyValueMax];
-    bool have_dex2oat_large_app_threshold =
-            get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, nullptr) > 0;
-    char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax];
-    if (have_dex2oat_large_app_threshold) {
-        sprintf(dex2oat_large_app_threshold_arg,
-                "--very-large-app-threshold=%s",
-                dex2oat_large_app_threshold);
-    }
-
-    // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
-    const char* dex2oat_bin = "/system/bin/dex2oat";
-    constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
-    // Do not use dex2oatd for release candidates (give dex2oat more soak time).
-    bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
-    if (is_debug_runtime() || (background_job_compile && is_debuggable_build() && !is_release)) {
-        if (access(kDex2oatDebugPath, X_OK) == 0) {
-            dex2oat_bin = kDex2oatDebugPath;
+    // Add an arg if it's not empty.
+    void AddArg(const std::string& arg) {
+        if (!arg.empty()) {
+            args_.push_back(arg);
         }
     }
 
-    bool generate_minidebug_info = kEnableMinidebugInfo &&
-            android::base::GetBoolProperty(kMinidebugInfoSystemProperty,
-                                           kMinidebugInfoSystemPropertyDefault);
-
-    static const char* RUNTIME_ARG = "--runtime-arg";
-
-    static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig
-
-    // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
-    // use arraysize instead.
-    char zip_fd_arg[arraysize("--zip-fd=") + MAX_INT_LEN];
-    char zip_location_arg[arraysize("--zip-location=") + PKG_PATH_MAX];
-    char input_vdex_fd_arg[arraysize("--input-vdex-fd=") + MAX_INT_LEN];
-    char output_vdex_fd_arg[arraysize("--output-vdex-fd=") + MAX_INT_LEN];
-    char oat_fd_arg[arraysize("--oat-fd=") + MAX_INT_LEN];
-    char oat_location_arg[arraysize("--oat-location=") + PKG_PATH_MAX];
-    char instruction_set_arg[arraysize("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
-    char instruction_set_variant_arg[arraysize("--instruction-set-variant=") + kPropertyValueMax];
-    char instruction_set_features_arg[arraysize("--instruction-set-features=") + kPropertyValueMax];
-    char dex2oat_Xms_arg[arraysize("-Xms") + kPropertyValueMax];
-    char dex2oat_Xmx_arg[arraysize("-Xmx") + kPropertyValueMax];
-    char dex2oat_compiler_filter_arg[arraysize("--compiler-filter=") + kPropertyValueMax];
-    bool have_dex2oat_swap_fd = false;
-    char dex2oat_swap_fd[arraysize("--swap-fd=") + MAX_INT_LEN];
-    bool have_dex2oat_image_fd = false;
-    char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];
-    size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX;
-    char target_sdk_version_arg[arraysize("-Xtarget-sdk-version:") + MAX_INT_LEN];
-    char class_loader_context_arg[class_loader_context_size];
-    if (class_loader_context != nullptr) {
-        snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s",
-            class_loader_context);
-    }
-
-    sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
-    sprintf(zip_location_arg, "--zip-location=%s", relative_input_file_name);
-    sprintf(input_vdex_fd_arg, "--input-vdex-fd=%d", input_vdex_fd);
-    sprintf(output_vdex_fd_arg, "--output-vdex-fd=%d", output_vdex_fd);
-    sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
-    sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
-    sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
-    sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant);
-    sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);
-    if (swap_fd >= 0) {
-        have_dex2oat_swap_fd = true;
-        sprintf(dex2oat_swap_fd, "--swap-fd=%d", swap_fd);
-    }
-    if (image_fd >= 0) {
-        have_dex2oat_image_fd = true;
-        sprintf(dex2oat_image_fd, "--app-image-fd=%d", image_fd);
-    }
-
-    if (have_dex2oat_Xms_flag) {
-        sprintf(dex2oat_Xms_arg, "-Xms%s", dex2oat_Xms_flag);
-    }
-    if (have_dex2oat_Xmx_flag) {
-        sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
-    }
-    sprintf(target_sdk_version_arg, "-Xtarget-sdk-version:%d", target_sdk_version);
-
-    // Compute compiler filter.
-
-    bool have_dex2oat_compiler_filter_flag = false;
-    if (skip_compilation) {
-        strlcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract",
-                sizeof(dex2oat_compiler_filter_arg));
-        have_dex2oat_compiler_filter_flag = true;
-        have_dex2oat_relocation_skip_flag = true;
-    } else if (compiler_filter != nullptr) {
-        if (strlen(compiler_filter) + strlen("--compiler-filter=") <
-                    arraysize(dex2oat_compiler_filter_arg)) {
-            sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
-            have_dex2oat_compiler_filter_flag = true;
-        } else {
-            ALOGW("Compiler filter name '%s' is too large (max characters is %zu)",
-                  compiler_filter,
-                  kPropertyValueMax);
+    // Add a runtime arg if it's not empty.
+    void AddRuntimeArg(const std::string& arg) {
+        if (!arg.empty()) {
+            args_.push_back("--runtime-arg");
+            args_.push_back(arg);
         }
     }
 
-    if (!have_dex2oat_compiler_filter_flag) {
-        char dex2oat_compiler_filter_flag[kPropertyValueMax];
-        have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",
-                                                         dex2oat_compiler_filter_flag, nullptr) > 0;
-        if (have_dex2oat_compiler_filter_flag) {
-            sprintf(dex2oat_compiler_filter_arg,
-                    "--compiler-filter=%s",
-                    dex2oat_compiler_filter_flag);
-        }
-    }
+  protected:
+    // Holder arrays for backing arg storage.
+    std::vector<std::string> args_;
 
-    // Check whether all apps should be compiled debuggable.
-    if (!debuggable) {
-        char prop_buf[kPropertyValueMax];
-        debuggable =
-                (get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&
-                (prop_buf[0] == '1');
-    }
-    char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN];
-    if (profile_fd != -1) {
-        sprintf(profile_arg, "--profile-file-fd=%d", profile_fd);
-    }
+    // Argument poiners.
+    std::vector<const char*> argv_;
+};
 
-    // Get the directory of the apk to pass as a base classpath directory.
-    char base_dir[arraysize("--classpath-dir=") + PKG_PATH_MAX];
-    std::string apk_dir(input_file_name);
-    unsigned long dir_index = apk_dir.rfind('/');
-    bool has_base_dir = dir_index != std::string::npos;
-    if (has_base_dir) {
-        apk_dir = apk_dir.substr(0, dir_index);
-        sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());
-    }
-
-    std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
-
-    std::string compilation_reason_arg = compilation_reason == nullptr
-            ? ""
-            : std::string("--compilation-reason=") + compilation_reason;
-
-    ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
-
-    // Disable cdex if update input vdex is true since this combination of options is not
-    // supported.
-    const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
-
-    const char* argv[9  // program name, mandatory arguments and the final NULL
-                     + (have_dex2oat_isa_variant ? 1 : 0)
-                     + (have_dex2oat_isa_features ? 1 : 0)
-                     + (have_dex2oat_Xms_flag ? 2 : 0)
-                     + (have_dex2oat_Xmx_flag ? 2 : 0)
-                     + (have_dex2oat_compiler_filter_flag ? 1 : 0)
-                     + (have_dex2oat_threads_flag ? 1 : 0)
-                     + (have_dex2oat_swap_fd ? 1 : 0)
-                     + (have_dex2oat_image_fd ? 1 : 0)
-                     + (have_dex2oat_relocation_skip_flag ? 2 : 0)
-                     + (generate_debug_info ? 1 : 0)
-                     + (debuggable ? 1 : 0)
-                     + (have_app_image_format ? 1 : 0)
-                     + dex2oat_flags_count
-                     + (profile_fd == -1 ? 0 : 1)
-                     + (class_loader_context != nullptr ? 1 : 0)
-                     + (has_base_dir ? 1 : 0)
-                     + (have_dex2oat_large_app_threshold ? 1 : 0)
-                     + (disable_cdex ? 1 : 0)
-                     + (generate_minidebug_info ? 1 : 0)
-                     + (target_sdk_version != 0 ? 2 : 0)
-                     + (enable_hidden_api_checks ? 2 : 0)
-                     + (dex_metadata_fd > -1 ? 1 : 0)
-                     + (compilation_reason != nullptr ? 1 : 0)];
-    int i = 0;
-    argv[i++] = dex2oat_bin;
-    argv[i++] = zip_fd_arg;
-    argv[i++] = zip_location_arg;
-    argv[i++] = input_vdex_fd_arg;
-    argv[i++] = output_vdex_fd_arg;
-    argv[i++] = oat_fd_arg;
-    argv[i++] = oat_location_arg;
-    argv[i++] = instruction_set_arg;
-    if (have_dex2oat_isa_variant) {
-        argv[i++] = instruction_set_variant_arg;
-    }
-    if (have_dex2oat_isa_features) {
-        argv[i++] = instruction_set_features_arg;
-    }
-    if (have_dex2oat_Xms_flag) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = dex2oat_Xms_arg;
-    }
-    if (have_dex2oat_Xmx_flag) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = dex2oat_Xmx_arg;
-    }
-    if (have_dex2oat_compiler_filter_flag) {
-        argv[i++] = dex2oat_compiler_filter_arg;
-    }
-    if (have_dex2oat_threads_flag) {
-        argv[i++] = dex2oat_threads_arg;
-    }
-    if (have_dex2oat_swap_fd) {
-        argv[i++] = dex2oat_swap_fd;
-    }
-    if (have_dex2oat_image_fd) {
-        argv[i++] = dex2oat_image_fd;
-    }
-    if (generate_debug_info) {
-        argv[i++] = "--generate-debug-info";
-    }
-    if (debuggable) {
-        argv[i++] = "--debuggable";
-    }
-    if (have_app_image_format) {
-        argv[i++] = image_format_arg;
-    }
-    if (have_dex2oat_large_app_threshold) {
-        argv[i++] = dex2oat_large_app_threshold_arg;
-    }
-    if (dex2oat_flags_count) {
-        i += split(dex2oat_flags, argv + i);
-    }
-    if (have_dex2oat_relocation_skip_flag) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = dex2oat_norelocation;
-    }
-    if (profile_fd != -1) {
-        argv[i++] = profile_arg;
-    }
-    if (has_base_dir) {
-        argv[i++] = base_dir;
-    }
-    if (class_loader_context != nullptr) {
-        argv[i++] = class_loader_context_arg;
-    }
-    if (generate_minidebug_info) {
-        argv[i++] = kMinidebugDex2oatFlag;
-    }
-    if (disable_cdex) {
-        argv[i++] = kDisableCompactDexFlag;
-    }
-    if (target_sdk_version != 0) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = target_sdk_version_arg;
-    }
-    if (enable_hidden_api_checks) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = "-Xhidden-api-checks";
-    }
-
-    if (dex_metadata_fd > -1) {
-        argv[i++] = dex_metadata_fd_arg.c_str();
-    }
-
-    if(compilation_reason != nullptr) {
-        argv[i++] = compilation_reason_arg.c_str();
-    }
-    // Do not add after dex2oat_flags, they should override others for debugging.
-    argv[i] = nullptr;
-
-    execv(dex2oat_bin, (char * const *)argv);
-    PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
-    exit(DexoptReturnCodes::kDex2oatExec);
+static std::string MapPropertyToArg(const std::string& property,
+                                    const std::string& format,
+                                    const std::string& default_value = "") {
+  std::string prop = GetProperty(property, default_value);
+  if (!prop.empty()) {
+    return StringPrintf(format.c_str(), prop.c_str());
+  }
+  return "";
 }
 
+class RunDex2Oat : public ExecVHelper {
+  public:
+    RunDex2Oat(int zip_fd,
+               int oat_fd,
+               int input_vdex_fd,
+               int output_vdex_fd,
+               int image_fd,
+               const char* input_file_name,
+               const char* output_file_name,
+               int swap_fd,
+               const char* instruction_set,
+               const char* compiler_filter,
+               bool debuggable,
+               bool post_bootcomplete,
+               bool background_job_compile,
+               int profile_fd,
+               const char* class_loader_context,
+               int target_sdk_version,
+               bool enable_hidden_api_checks,
+               bool generate_compact_dex,
+               int dex_metadata_fd,
+               const char* compilation_reason) {
+        // Get the relative path to the input file.
+        const char* relative_input_file_name = get_location_from_path(input_file_name);
+
+        std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
+        std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
+
+        const char* threads_property = post_bootcomplete
+                ? "dalvik.vm.dex2oat-threads"
+                : "dalvik.vm.boot-dex2oat-threads";
+        std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
+
+        const std::string dex2oat_isa_features_key =
+                StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
+        std::string instruction_set_features_arg =
+            MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
+
+        const std::string dex2oat_isa_variant_key =
+                StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
+        std::string instruction_set_variant_arg =
+            MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
+
+        const char* dex2oat_norelocation = "-Xnorelocate";
+
+        const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
+        std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
+        ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
+
+        // If we are booting without the real /data, don't spend time compiling.
+        std::string vold_decrypt = GetProperty("vold.decrypt", "");
+        bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
+                                vold_decrypt == "1";
+
+        const std::string resolve_startup_string_arg  =
+                MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
+                                 "--resolve-startup-const-strings=%s");
+        const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
+
+        std::string image_format_arg;
+        if (image_fd >= 0) {
+            image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
+        }
+
+        std::string dex2oat_large_app_threshold_arg =
+            MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
+
+        // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
+        const char* dex2oat_bin = "/system/bin/dex2oat";
+        constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+        // Do not use dex2oatd for release candidates (give dex2oat more soak time).
+        bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
+        if (is_debug_runtime() ||
+                (background_job_compile && is_debuggable_build() && !is_release)) {
+            if (access(kDex2oatDebugPath, X_OK) == 0) {
+                dex2oat_bin = kDex2oatDebugPath;
+            }
+        }
+
+        bool generate_minidebug_info = kEnableMinidebugInfo &&
+                GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
+
+        // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
+        // use arraysize instead.
+        std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
+        std::string zip_location_arg = StringPrintf("--zip-location=%s", relative_input_file_name);
+        std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
+        std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
+        std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
+        std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
+        std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
+        std::string dex2oat_compiler_filter_arg;
+        std::string dex2oat_swap_fd;
+        std::string dex2oat_image_fd;
+        std::string target_sdk_version_arg;
+        if (target_sdk_version != 0) {
+            StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
+        }
+        std::string class_loader_context_arg;
+        if (class_loader_context != nullptr) {
+            class_loader_context_arg = StringPrintf("--class-loader-context=%s",
+                                                    class_loader_context);
+        }
+
+        if (swap_fd >= 0) {
+            dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
+        }
+        if (image_fd >= 0) {
+            dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
+        }
+
+        // Compute compiler filter.
+        bool have_dex2oat_relocation_skip_flag = false;
+        if (skip_compilation) {
+            dex2oat_compiler_filter_arg = "--compiler-filter=extract";
+            have_dex2oat_relocation_skip_flag = true;
+        } else if (compiler_filter != nullptr) {
+            dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
+        }
+
+        if (dex2oat_compiler_filter_arg.empty()) {
+            dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
+                                                           "--compiler-filter=%s");
+        }
+
+        // Check whether all apps should be compiled debuggable.
+        if (!debuggable) {
+            debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
+        }
+        std::string profile_arg;
+        if (profile_fd != -1) {
+            profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
+        }
+
+        // Get the directory of the apk to pass as a base classpath directory.
+        std::string base_dir;
+        std::string apk_dir(input_file_name);
+        unsigned long dir_index = apk_dir.rfind('/');
+        bool has_base_dir = dir_index != std::string::npos;
+        if (has_base_dir) {
+            apk_dir = apk_dir.substr(0, dir_index);
+            base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
+        }
+
+        std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
+
+        std::string compilation_reason_arg = compilation_reason == nullptr
+                ? ""
+                : std::string("--compilation-reason=") + compilation_reason;
+
+        ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
+
+        // Disable cdex if update input vdex is true since this combination of options is not
+        // supported.
+        const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
+
+        AddArg(zip_fd_arg);
+        AddArg(zip_location_arg);
+        AddArg(input_vdex_fd_arg);
+        AddArg(output_vdex_fd_arg);
+        AddArg(oat_fd_arg);
+        AddArg(oat_location_arg);
+        AddArg(instruction_set_arg);
+
+        AddArg(instruction_set_variant_arg);
+        AddArg(instruction_set_features_arg);
+
+        AddRuntimeArg(dex2oat_Xms_arg);
+        AddRuntimeArg(dex2oat_Xmx_arg);
+
+        AddArg(resolve_startup_string_arg);
+        AddArg(dex2oat_compiler_filter_arg);
+        AddArg(dex2oat_threads_arg);
+        AddArg(dex2oat_swap_fd);
+        AddArg(dex2oat_image_fd);
+
+        if (generate_debug_info) {
+            AddArg("--generate-debug-info");
+        }
+        if (debuggable) {
+            AddArg("--debuggable");
+        }
+        AddArg(image_format_arg);
+        AddArg(dex2oat_large_app_threshold_arg);
+
+        if (have_dex2oat_relocation_skip_flag) {
+            AddRuntimeArg(dex2oat_norelocation);
+        }
+        AddArg(profile_arg);
+        AddArg(base_dir);
+        AddArg(class_loader_context_arg);
+        if (generate_minidebug_info) {
+            AddArg(kMinidebugDex2oatFlag);
+        }
+        if (disable_cdex) {
+            AddArg(kDisableCompactDexFlag);
+        }
+        AddArg(target_sdk_version_arg);
+        if (enable_hidden_api_checks) {
+            AddRuntimeArg("-Xhidden-api-checks");
+        }
+
+        if (dex_metadata_fd > -1) {
+            AddArg(dex_metadata_fd_arg);
+        }
+
+        AddArg(compilation_reason_arg);
+
+        // Do not add args after dex2oat_flags, they should override others for debugging.
+        args_.insert(args_.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end());
+
+        PrepareArgs(dex2oat_bin);
+    }
+};
+
 /*
  * Whether dexopt should use a swap file when compiling an APK.
  *
@@ -580,13 +495,9 @@
     }
 
     // Check the "override" property. If it exists, return value == "true".
-    char dex2oat_prop_buf[kPropertyValueMax];
-    if (get_property("dalvik.vm.dex2oat-swap", dex2oat_prop_buf, "") > 0) {
-        if (strcmp(dex2oat_prop_buf, "true") == 0) {
-            return true;
-        } else {
-            return false;
-        }
+    std::string dex2oat_prop_buf = GetProperty("dalvik.vm.dex2oat-swap", "");
+    if (!dex2oat_prop_buf.empty()) {
+        return dex2oat_prop_buf == "true";
     }
 
     // Shortcut for default value. This is an implementation optimization for the process sketched
@@ -596,8 +507,7 @@
         return true;
     }
 
-    bool is_low_mem = property_get_bool("ro.config.low_ram", false);
-    if (is_low_mem) {
+    if (GetBoolProperty("ro.config.low_ram", false)) {
         return true;
     }
 
@@ -738,91 +648,91 @@
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
 
-[[ noreturn ]]
-static void run_profman(const std::vector<unique_fd>& profile_fds,
-                        const unique_fd& reference_profile_fd,
-                        const std::vector<unique_fd>* apk_fds,
-                        const std::vector<std::string>* dex_locations,
-                        bool copy_and_update) {
-    const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
+class RunProfman : public ExecVHelper {
+  public:
+   void SetupArgs(const std::vector<unique_fd>& profile_fds,
+                  const unique_fd& reference_profile_fd,
+                  const std::vector<unique_fd>& apk_fds,
+                  const std::vector<std::string>& dex_locations,
+                  bool copy_and_update) {
+        const char* profman_bin =
+                is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
 
-    if (copy_and_update) {
-        CHECK_EQ(1u, profile_fds.size());
-        CHECK(apk_fds != nullptr);
-        CHECK_EQ(1u, apk_fds->size());
-    }
-    std::vector<std::string> profile_args(profile_fds.size());
-    for (size_t k = 0; k < profile_fds.size(); k++) {
-        profile_args[k] = "--profile-file-fd=" + std::to_string(profile_fds[k].get());
-    }
-    std::string reference_profile_arg = "--reference-profile-file-fd="
-            + std::to_string(reference_profile_fd.get());
-
-    std::vector<std::string> apk_args;
-    if (apk_fds != nullptr) {
-        for (size_t k = 0; k < apk_fds->size(); k++) {
-            apk_args.push_back("--apk-fd=" + std::to_string((*apk_fds)[k].get()));
+        if (copy_and_update) {
+            CHECK_EQ(1u, profile_fds.size());
+            CHECK_EQ(1u, apk_fds.size());
         }
-    }
-
-    std::vector<std::string> dex_location_args;
-    if (dex_locations != nullptr) {
-        for (size_t k = 0; k < dex_locations->size(); k++) {
-            dex_location_args.push_back("--dex-location=" + (*dex_locations)[k]);
+        if (reference_profile_fd != -1) {
+            AddArg("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
         }
+
+        for (const unique_fd& fd : profile_fds) {
+            AddArg("--profile-file-fd=" + std::to_string(fd.get()));
+        }
+
+        for (const unique_fd& fd : apk_fds) {
+            AddArg("--apk-fd=" + std::to_string(fd.get()));
+        }
+
+        for (const std::string& dex_location : dex_locations) {
+            AddArg("--dex-location=" + dex_location);
+        }
+
+        if (copy_and_update) {
+            AddArg("--copy-and-update-profile-key");
+        }
+
+        // Do not add after dex2oat_flags, they should override others for debugging.
+        PrepareArgs(profman_bin);
     }
 
-    // program name, reference profile fd, the final NULL and the profile fds
-    const char* argv[3 + profile_args.size() + apk_args.size()
-            + dex_location_args.size() + (copy_and_update ? 1 : 0)];
-    int i = 0;
-    argv[i++] = profman_bin;
-    argv[i++] = reference_profile_arg.c_str();
-    for (size_t k = 0; k < profile_args.size(); k++) {
-        argv[i++] = profile_args[k].c_str();
-    }
-    for (size_t k = 0; k < apk_args.size(); k++) {
-        argv[i++] = apk_args[k].c_str();
-    }
-    for (size_t k = 0; k < dex_location_args.size(); k++) {
-        argv[i++] = dex_location_args[k].c_str();
-    }
-    if (copy_and_update) {
-        argv[i++] = "--copy-and-update-profile-key";
+    void SetupMerge(const std::vector<unique_fd>& profiles_fd,
+                    const unique_fd& reference_profile_fd,
+                    const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>(),
+                    const std::vector<std::string>& dex_locations = std::vector<std::string>()) {
+        SetupArgs(profiles_fd,
+                    reference_profile_fd,
+                    apk_fds,
+                    dex_locations,
+                    /*copy_and_update=*/false);
     }
 
-    // Do not add after dex2oat_flags, they should override others for debugging.
-    argv[i] = nullptr;
+    void SetupCopyAndUpdate(unique_fd&& profile_fd,
+                            unique_fd&& reference_profile_fd,
+                            unique_fd&& apk_fd,
+                            const std::string& dex_location) {
+        // The fds need to stay open longer than the scope of the function, so put them into a local
+        // variable vector.
+        profiles_fd_.push_back(std::move(profile_fd));
+        apk_fds_.push_back(std::move(apk_fd));
+        reference_profile_fd_ = std::move(reference_profile_fd);
+        std::vector<std::string> dex_locations = {dex_location};
+        SetupArgs(profiles_fd_, reference_profile_fd_, apk_fds_, dex_locations,
+                  /*copy_and_update=*/true);
+    }
 
-    execv(profman_bin, (char * const *)argv);
-    PLOG(ERROR) << "execv(" << profman_bin << ") failed";
-    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
-}
+    void SetupDump(const std::vector<unique_fd>& profiles_fd,
+                   const unique_fd& reference_profile_fd,
+                   const std::vector<std::string>& dex_locations,
+                   const std::vector<unique_fd>& apk_fds,
+                   const unique_fd& output_fd) {
+        AddArg("--dump-only");
+        AddArg(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
+        SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
+                  /*copy_and_update=*/false);
+    }
 
-[[ noreturn ]]
-static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
-                              const unique_fd& reference_profile_fd,
-                              const std::vector<unique_fd>* apk_fds = nullptr,
-                              const std::vector<std::string>* dex_locations = nullptr) {
-    run_profman(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
-            /*copy_and_update*/false);
-}
+    void Exec() {
+        ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
+    }
 
-[[ noreturn ]]
-static void run_profman_copy_and_update(unique_fd&& profile_fd,
-                                        unique_fd&& reference_profile_fd,
-                                        unique_fd&& apk_fd,
-                                        const std::string& dex_location) {
-    std::vector<unique_fd> profiles_fd;
-    profiles_fd.push_back(std::move(profile_fd));
-    std::vector<unique_fd> apk_fds;
-    apk_fds.push_back(std::move(apk_fd));
-    std::vector<std::string> dex_locations;
-    dex_locations.push_back(dex_location);
+  private:
+    unique_fd reference_profile_fd_;
+    std::vector<unique_fd> profiles_fd_;
+    std::vector<unique_fd> apk_fds_;
+};
 
-    run_profman(profiles_fd, reference_profile_fd, &apk_fds, &dex_locations,
-            /*copy_and_update*/true);
-}
+
 
 // Decides if profile guided compilation is needed or not based on existing profiles.
 // The location is the package name for primary apks or the dex path for secondary dex files.
@@ -842,11 +752,13 @@
         return false;
     }
 
+    RunProfman profman_merge;
+    profman_merge.SetupMerge(profiles_fd, reference_profile_fd);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
-        run_profman_merge(profiles_fd, reference_profile_fd);
+        profman_merge.Exec();
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -919,42 +831,6 @@
     return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false);
 }
 
-[[ noreturn ]]
-static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
-                             const unique_fd& reference_profile_fd,
-                             const std::vector<std::string>& dex_locations,
-                             const std::vector<unique_fd>& apk_fds,
-                             const unique_fd& output_fd) {
-    std::vector<std::string> profman_args;
-    static const char* PROFMAN_BIN = "/system/bin/profman";
-    profman_args.push_back(PROFMAN_BIN);
-    profman_args.push_back("--dump-only");
-    profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
-    if (reference_profile_fd != -1) {
-        profman_args.push_back(StringPrintf("--reference-profile-file-fd=%d",
-                                            reference_profile_fd.get()));
-    }
-    for (size_t i = 0; i < profile_fds.size(); i++) {
-        profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fds[i].get()));
-    }
-    for (const std::string& dex_location : dex_locations) {
-        profman_args.push_back(StringPrintf("--dex-location=%s", dex_location.c_str()));
-    }
-    for (size_t i = 0; i < apk_fds.size(); i++) {
-        profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fds[i].get()));
-    }
-    const char **argv = new const char*[profman_args.size() + 1];
-    size_t i = 0;
-    for (const std::string& profman_arg : profman_args) {
-        argv[i++] = profman_arg.c_str();
-    }
-    argv[i] = nullptr;
-
-    execv(PROFMAN_BIN, (char * const *)argv);
-    PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
-    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
-}
-
 bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
         const std::string& code_path) {
     std::vector<unique_fd> profile_fds;
@@ -991,12 +867,13 @@
     apk_fds.push_back(std::move(apk_fd));
 
 
+    RunProfman profman_dump;
+    profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds, output_fd);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
-        run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
-                         apk_fds, output_fd);
+        profman_dump.Exec();
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -1306,10 +1183,8 @@
     if (!generate_app_image) {
         return Dex2oatFileWrapper();
     }
-    char app_image_format[kPropertyValueMax];
-    bool have_app_image_format =
-            get_property("dalvik.vm.appimageformat", app_image_format, nullptr) > 0;
-    if (!have_app_image_format) {
+    std::string app_image_format = GetProperty("dalvik.vm.appimageformat", "");
+    if (app_image_format.empty()) {
         return Dex2oatFileWrapper();
     }
     // Recreate is true since we do not want to modify a mapped image. If the app is
@@ -1570,70 +1445,60 @@
 // The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
 // If this is for a profile guided compilation, profile_was_updated will tell whether or not
 // the profile has changed.
-static void exec_dexoptanalyzer(const std::string& dex_file, int vdex_fd, int oat_fd,
-        int zip_fd, const std::string& instruction_set, const std::string& compiler_filter,
-        bool profile_was_updated, bool downgrade,
-        const char* class_loader_context) {
-    CHECK_GE(zip_fd, 0);
-    const char* dexoptanalyzer_bin =
-            is_debug_runtime()
-                    ? "/system/bin/dexoptanalyzerd"
-                    : "/system/bin/dexoptanalyzer";
-    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+class RunDexoptAnalyzer : public ExecVHelper {
+ public:
+    RunDexoptAnalyzer(const std::string& dex_file,
+                    int vdex_fd,
+                    int oat_fd,
+                    int zip_fd,
+                    const std::string& instruction_set,
+                    const std::string& compiler_filter,
+                    bool profile_was_updated,
+                    bool downgrade,
+                    const char* class_loader_context) {
+        CHECK_GE(zip_fd, 0);
+        const char* dexoptanalyzer_bin =
+                is_debug_runtime()
+                        ? "/system/bin/dexoptanalyzerd"
+                        : "/system/bin/dexoptanalyzer";
 
-    if (instruction_set.size() >= MAX_INSTRUCTION_SET_LEN) {
-        LOG(ERROR) << "Instruction set " << instruction_set
-                << " longer than max length of " << MAX_INSTRUCTION_SET_LEN;
-        return;
-    }
+        std::string dex_file_arg = "--dex-file=" + dex_file;
+        std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
+        std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
+        std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
+        std::string isa_arg = "--isa=" + instruction_set;
+        std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
+        const char* assume_profile_changed = "--assume-profile-changed";
+        const char* downgrade_flag = "--downgrade";
+        std::string class_loader_context_arg = "--class-loader-context=";
+        if (class_loader_context != nullptr) {
+            class_loader_context_arg += class_loader_context;
+        }
 
-    std::string dex_file_arg = "--dex-file=" + dex_file;
-    std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
-    std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
-    std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
-    std::string isa_arg = "--isa=" + instruction_set;
-    std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
-    const char* assume_profile_changed = "--assume-profile-changed";
-    const char* downgrade_flag = "--downgrade";
-    std::string class_loader_context_arg = "--class-loader-context=";
-    if (class_loader_context != nullptr) {
-        class_loader_context_arg += class_loader_context;
-    }
+        // program name, dex file, isa, filter
+        AddArg(dex_file_arg);
+        AddArg(isa_arg);
+        AddArg(compiler_filter_arg);
+        if (oat_fd >= 0) {
+            AddArg(oat_fd_arg);
+        }
+        if (vdex_fd >= 0) {
+            AddArg(vdex_fd_arg);
+        }
+        AddArg(zip_fd_arg.c_str());
+        if (profile_was_updated) {
+            AddArg(assume_profile_changed);
+        }
+        if (downgrade) {
+            AddArg(downgrade_flag);
+        }
+        if (class_loader_context != nullptr) {
+            AddArg(class_loader_context_arg.c_str());
+        }
 
-    // program name, dex file, isa, filter, the final NULL
-    const int argc = 6 +
-        (profile_was_updated ? 1 : 0) +
-        (vdex_fd >= 0 ? 1 : 0) +
-        (oat_fd >= 0 ? 1 : 0) +
-        (downgrade ? 1 : 0) +
-        (class_loader_context != nullptr ? 1 : 0);
-    const char* argv[argc];
-    int i = 0;
-    argv[i++] = dexoptanalyzer_bin;
-    argv[i++] = dex_file_arg.c_str();
-    argv[i++] = isa_arg.c_str();
-    argv[i++] = compiler_filter_arg.c_str();
-    if (oat_fd >= 0) {
-        argv[i++] = oat_fd_arg.c_str();
+        PrepareArgs(dexoptanalyzer_bin);
     }
-    if (vdex_fd >= 0) {
-        argv[i++] = vdex_fd_arg.c_str();
-    }
-    argv[i++] = zip_fd_arg.c_str();
-    if (profile_was_updated) {
-        argv[i++] = assume_profile_changed;
-    }
-    if (downgrade) {
-        argv[i++] = downgrade_flag;
-    }
-    if (class_loader_context != nullptr) {
-        argv[i++] = class_loader_context_arg.c_str();
-    }
-    argv[i] = nullptr;
-
-    execv(dexoptanalyzer_bin, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
-}
+};
 
 // Prepares the oat dir for the secondary dex files.
 static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
@@ -1885,16 +1750,17 @@
                 /*is_secondary_dex*/true);
 
         // Run dexoptanalyzer to get dexopt_needed code. This is not expected to return.
-        exec_dexoptanalyzer(dex_path,
-                            vdex_file_fd.get(),
-                            oat_file_fd.get(),
-                            zip_fd.get(),
-                            instruction_set,
-                            compiler_filter, profile_was_updated,
-                            downgrade,
-                            class_loader_context);
-        PLOG(ERROR) << "Failed to exec dexoptanalyzer";
-        _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec);
+        // Note that we do not do it before the fork since opening the files is required to happen
+        // after forking.
+        RunDexoptAnalyzer run_dexopt_analyzer(dex_path,
+                                              vdex_file_fd.get(),
+                                              oat_file_fd.get(),
+                                              zip_fd.get(),
+                                              instruction_set,
+                                              compiler_filter, profile_was_updated,
+                                              downgrade,
+                                              class_loader_context);
+        run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
     }
 
     /* parent */
@@ -2063,6 +1929,27 @@
 
     LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
 
+    RunDex2Oat runner(input_fd.get(),
+                      out_oat_fd.get(),
+                      in_vdex_fd.get(),
+                      out_vdex_fd.get(),
+                      image_fd.get(),
+                      dex_path,
+                      out_oat_path,
+                      swap_fd.get(),
+                      instruction_set,
+                      compiler_filter,
+                      debuggable,
+                      boot_complete,
+                      background_job_compile,
+                      reference_profile_fd.get(),
+                      class_loader_context,
+                      target_sdk_version,
+                      enable_hidden_api_checks,
+                      generate_compact_dex,
+                      dex_metadata_fd.get(),
+                      compilation_reason);
+
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
@@ -2074,26 +1961,7 @@
             _exit(DexoptReturnCodes::kFlock);
         }
 
-        run_dex2oat(input_fd.get(),
-                    out_oat_fd.get(),
-                    in_vdex_fd.get(),
-                    out_vdex_fd.get(),
-                    image_fd.get(),
-                    dex_path,
-                    out_oat_path,
-                    swap_fd.get(),
-                    instruction_set,
-                    compiler_filter,
-                    debuggable,
-                    boot_complete,
-                    background_job_compile,
-                    reference_profile_fd.get(),
-                    class_loader_context,
-                    target_sdk_version,
-                    enable_hidden_api_checks,
-                    generate_compact_dex,
-                    dex_metadata_fd.get(),
-                    compilation_reason);
+        runner.Exec(DexoptReturnCodes::kDex2oatExec);
     } else {
         int res = wait_child(pid);
         if (res == 0) {
@@ -2421,18 +2289,14 @@
 
 bool move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) {
     // Get the current slot suffix. No suffix, no A/B.
-    std::string slot_suffix;
-    {
-        char buf[kPropertyValueMax];
-        if (get_property("ro.boot.slot_suffix", buf, nullptr) <= 0) {
-            return false;
-        }
-        slot_suffix = buf;
+    const std::string slot_suffix = GetProperty("ro.boot.slot_suffix", "");
+    if (slot_suffix.empty()) {
+        return false;
+    }
 
-        if (!ValidateTargetSlotSuffix(slot_suffix)) {
-            LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
-            return false;
-        }
+    if (!ValidateTargetSlotSuffix(slot_suffix)) {
+        LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
+        return false;
     }
 
     // Validate other inputs.
@@ -2661,11 +2525,13 @@
         return false;
     }
 
+    RunProfman args;
+    args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(app_shared_gid);
-        run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
+        args.Exec();
     }
 
     /* parent */
@@ -2689,6 +2555,13 @@
         return false;
     }
 
+    // Return false for empty class path since it may otherwise return true below if profiles is
+    // empty.
+    if (classpath.empty()) {
+        PLOG(ERROR) << "Class path is empty";
+        return false;
+    }
+
     // Open and create the snapshot profile.
     unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name);
 
@@ -2738,6 +2611,8 @@
                 profiles_fd.push_back(std::move(fd));
             }
         }
+        RunProfman args;
+        args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations);
         pid_t pid = fork();
         if (pid == 0) {
             /* child -- drop privileges before continuing */
@@ -2745,7 +2620,7 @@
 
             // The introduction of new access flags into boot jars causes them to
             // fail dex file verification.
-            run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
+            args.Exec();
         }
 
         /* parent */
@@ -2799,6 +2674,11 @@
         return false;
     }
 
+    RunProfman args;
+    args.SetupCopyAndUpdate(std::move(dex_metadata_fd),
+                            std::move(ref_profile_fd),
+                            std::move(apk_fd),
+                            code_path);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
@@ -2806,10 +2686,7 @@
         drop_capabilities(app_shared_gid);
 
         // The copy and update takes ownership over the fds.
-        run_profman_copy_and_update(std::move(dex_metadata_fd),
-                                    std::move(ref_profile_fd),
-                                    std::move(apk_fd),
-                                    code_path);
+        args.Exec();
     }
 
     /* parent */
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index f216c53..79e6859 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -143,6 +143,20 @@
     "AAAACADojmFLPcugSwoBAAAUAgAACwAYAAAAAAAAAAAAoIEAAAAAY2xhc3Nlcy5kZXhVVAUAA/Ns"
     "+ll1eAsAAQQj5QIABIgTAABQSwUGAAAAAAEAAQBRAAAATwEAAAAA";
 
+class DexoptTestEnvTest : public testing::Test {
+};
+
+TEST_F(DexoptTestEnvTest, CheckSelinux) {
+    ASSERT_EQ(1, is_selinux_enabled());
+
+    // Crude cutout for virtual devices.
+#if !defined(__i386__) && !defined(__x86_64__)
+    constexpr bool kIsX86 = false;
+#else
+    constexpr bool kIsX86 = true;
+#endif
+    ASSERT_TRUE(1 == security_getenforce() || kIsX86 || true /* b/119032200 */);
+}
 
 class DexoptTest : public testing::Test {
 protected:
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 6b9cf0d..74ad184 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -43,6 +43,7 @@
 #define DEBUG_XATTRS 0
 
 using android::base::EndsWith;
+using android::base::Fdopendir;
 using android::base::StringPrintf;
 using android::base::unique_fd;
 
@@ -1036,7 +1037,7 @@
                 continue;
             }
 
-            DIR* subdir = fdopendir(subdir_fd);
+            DIR* subdir = Fdopendir(std::move(subdir_fd));
             if (subdir == nullptr) {
                 PLOG(WARNING) << "Could not open dir path " << local_path;
                 result = false;
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 5829c4f..d05724a 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -36,8 +36,6 @@
 #define BYPASS_QUOTA 0
 #define BYPASS_SDCARDFS 0
 
-#define APPLY_HARD_QUOTAS 0
-
 namespace android {
 namespace installd {
 
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index 4d93cb4..152ac28 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -13,5 +13,6 @@
     onrestart restart cameraserver
     onrestart restart keystore
     onrestart restart gatekeeperd
+    onrestart restart thermalservice
     writepid /dev/cpuset/system-background/tasks
     shutdown critical
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 68ddeb0..c169b76 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -160,7 +160,7 @@
 message DisplayCreation {
     required int32     id                = 1;
     required string    name              = 2;
-    required int32     type              = 3;
+    optional uint64    display_id        = 3;
     required bool      is_secure         = 4;
 }
 
diff --git a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
index a892e46..d63d97f 100644
--- a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
+++ b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
@@ -172,7 +172,7 @@
 def display_create(increment):
     increment.display_creation.id = int(input("Enter id: "))
     increment.display_creation.name = str(raw_input("Enter name: "))
-    increment.display_creation.type = int(input("Enter type: "))
+    increment.display_creation.display_id = int(input("Enter display ID: "))
     increment.display_creation.is_secure = bool(input("Enter if secure: "))
 
 def display_delete(increment):
diff --git a/headers/media_plugin/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h
index c44a1f6..aa8bd3d 100644
--- a/headers/media_plugin/media/drm/DrmAPI.h
+++ b/headers/media_plugin/media/drm/DrmAPI.h
@@ -167,6 +167,25 @@
             kSecurityLevelHwSecureAll
         };
 
+        // An offline license may be usable or inactive. The keys in a
+        // usable offline license are available for decryption. When
+        // the offline license state is inactive, the keys have been
+        // marked for release using getKeyRequest with
+        // kKeyType_Release but the key response has not been
+        // received. The keys in an inactive offline license are not
+        // usable for decryption.
+
+        enum OfflineLicenseState {
+            // The offline license state is unknown due to an error
+            kOfflineLicenseStateUnknown,
+            // Offline license state is usable, the keys may be used for decryption.
+            kOfflineLicenseStateUsable,
+            // Offline license state is inactive, the keys have been marked for
+            // release using getKeyRequest() with kKeyType_Release but the
+            // key response has not been received.
+            kOfflineLicenseStateInactive
+        };
+
         DrmPlugin() {}
         virtual ~DrmPlugin() {}
 
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
index 79f666b..c541511 100644
--- a/include/android/system_fonts.h
+++ b/include/android/system_fonts.h
@@ -150,19 +150,81 @@
  * Move to the next system font.
  *
  * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
- * \return true if more system fonts are available, otherwise false.
+ * \return a font. If no more font is available, returns nullptr. You need to release the returned
+ *         font by ASystemFont_close when it is no longer needed.
  */
 ASystemFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29);
 
 /**
  * Close an ASystemFont returned by ASystemFontIterator_next.
  *
- * \param font a font returned by ASystemFontIterator_next. Do nothing if NULL is passed.
+ * \param font a font returned by ASystemFontIterator_next or ASystemFont_matchFamilyStyleCharacter.
+ *        Do nothing if NULL is passed.
  */
 void ASystemFont_close(ASystemFont* _Nullable font) __INTRODUCED_IN(29);
 
 
 /**
+ * Select the best font from given parameters.
+ *
+ * Only generic font families are supported.
+ * For more information about generic font families, read [W3C spec](https://www.w3.org/TR/css-fonts-4/#generic-font-families)
+ *
+ * Even if no font can render the given text, this function will return a non-null result for
+ * drawing Tofu character.
+ *
+ * Examples:
+ * <code>
+ *  // Simple font query for the ASCII character.
+ *  std::vector<uint16_t> text = { 'A' };
+ *  ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ *      "sans", 400, false, "en-US", text.data(), text.length(), &runLength);
+ *  // runLength will be 1 and the font will points a valid font file.
+ *
+ *  // Querying font for CJK characters
+ *  std::vector<uint16_t> text = { 0x9AA8 };
+ *  ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ *      "sans", 400, false, "zh-CN,ja-JP", text.data(), text.length(), &runLength);
+ *  // runLength will be 1 and the font will points a Simplified Chinese font.
+ *  ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ *      "sans", 400, false, "ja-JP,zh-CN", text.data(), text.length(), &runLength);
+ *  // runLength will be 1 and the font will points a Japanese font.
+ *
+ *  // Querying font for text/color emoji
+ *  std::vector<uint16_t> text = { 0xD83D, 0xDC68, 0x200D, 0x2764, 0xFE0F, 0x200D, 0xD83D, 0xDC68 };
+ *  ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ *      "sans", 400, false, "en-US", text.data(), text.length(), &runLength);
+ *  // runLength will be 8 and the font will points a color emoji font.
+ *
+ *  // Mixture of multiple script of characters.
+ *  // 0x05D0 is a Hebrew character and 0x0E01 is a Thai character.
+ *  std::vector<uint16_t> text = { 0x05D0, 0x0E01 };
+ *  ASystemFont font = ASystemFont_matchFamilyStyleCharacter(
+ *      "sans", 400, false, "en-US", text.data(), text.length(), &runLength);
+ *  // runLength will be 1 and the font will points a Hebrew font.
+ * </code>
+ *
+ * \param familyName a null character terminated font family name
+ * \param weight a font weight value. Only from 0 to 1000 value is valid
+ * \param italic true if italic, otherwise false.
+ * \param languageTags a null character terminated comma separated IETF BCP47 compliant language
+ *                     tags.
+ * \param text a UTF-16 encoded text buffer to be rendered.
+ * \param textLength a length of the given text buffer.
+ * \param runLengthOut if not null, the font run length will be filled.
+ * \return a font to be used for given text and params. You need to release the returned font by
+ *         ASystemFont_close when it is no longer needed.
+ */
+ASystemFont* _Nonnull ASystemFont_matchFamilyStyleCharacter(
+        const char* _Nonnull familyName,
+        uint16_t weight,
+        bool italic,
+        const char* _Nonnull languageTags,
+        const uint16_t* _Nonnull text,
+        uint32_t textLength,
+        uint32_t* _Nullable runLengthOut) __INTRODUCED_IN(29);
+
+/**
  * Return an absolute path to the current font file.
  *
  * Here is a list of font formats returned by this method:
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 1bd7c4f..f6cc3af 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -115,6 +115,7 @@
     return sEmptyDescriptor;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BBinder::transact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -137,6 +138,7 @@
     return err;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BBinder::linkToDeath(
     const sp<DeathRecipient>& /*recipient*/, void* /*cookie*/,
     uint32_t /*flags*/)
@@ -144,6 +146,7 @@
     return INVALID_OPERATION;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BBinder::unlinkToDeath(
     const wp<DeathRecipient>& /*recipient*/, void* /*cookie*/,
     uint32_t /*flags*/, wp<DeathRecipient>* /*outRecipient*/)
@@ -208,6 +211,7 @@
 }
 
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BBinder::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
 {
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 7342126..ec170f7 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -206,6 +206,7 @@
     return err;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BpBinder::transact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -220,6 +221,7 @@
     return DEAD_OBJECT;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BpBinder::linkToDeath(
     const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
 {
@@ -254,6 +256,7 @@
     return DEAD_OBJECT;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BpBinder::unlinkToDeath(
     const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
     wp<DeathRecipient>* outRecipient)
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp
index f9ec593..2f4dbee 100644
--- a/libs/binder/IAppOpsCallback.cpp
+++ b/libs/binder/IAppOpsCallback.cpp
@@ -49,6 +49,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnAppOpsCallback::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 068664b..fb0d521 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -129,6 +129,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnAppOpsService::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index ad1e69f..b307e3e 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -136,6 +136,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnBatteryStats::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 507ce53..caf2318 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -86,7 +86,7 @@
     virtual void* getBase() const;
     virtual size_t getSize() const;
     virtual uint32_t getFlags() const;
-    virtual uint32_t getOffset() const;
+    off_t getOffset() const override;
 
 private:
     friend class IMemory;
@@ -113,7 +113,7 @@
     mutable void*       mBase;
     mutable size_t      mSize;
     mutable uint32_t    mFlags;
-    mutable uint32_t    mOffset;
+    mutable off_t       mOffset;
     mutable bool        mRealHeap;
     mutable Mutex       mLock;
 };
@@ -129,6 +129,7 @@
 public:
     explicit BpMemory(const sp<IBinder>& impl);
     virtual ~BpMemory();
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const;
 
 private:
@@ -180,6 +181,7 @@
 {
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
 {
     if (mHeap == nullptr) {
@@ -187,13 +189,16 @@
         data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
         if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
             sp<IBinder> heap = reply.readStrongBinder();
-            ssize_t o = reply.readInt32();
-            size_t s = reply.readInt32();
             if (heap != nullptr) {
                 mHeap = interface_cast<IMemoryHeap>(heap);
                 if (mHeap != nullptr) {
+                    const int64_t offset64 = reply.readInt64();
+                    const uint64_t size64 = reply.readUint64();
+                    const ssize_t o = (ssize_t)offset64;
+                    const size_t s = (size_t)size64;
                     size_t heapSize = mHeap->getSize();
-                    if (s <= heapSize
+                    if (s == size64 && o == offset64 // ILP32 bounds check
+                            && s <= heapSize
                             && o >= 0
                             && (static_cast<size_t>(o) <= heapSize - s)) {
                         mOffset = o;
@@ -224,6 +229,7 @@
 BnMemory::~BnMemory() {
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnMemory::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -233,8 +239,8 @@
             ssize_t offset;
             size_t size;
             reply->writeStrongBinder( IInterface::asBinder(getMemory(&offset, &size)) );
-            reply->writeInt32(offset);
-            reply->writeInt32(size);
+            reply->writeInt64(offset);
+            reply->writeUint64(size);
             return NO_ERROR;
         } break;
         default:
@@ -313,18 +319,23 @@
         data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
         status_t err = remote()->transact(HEAP_ID, data, &reply);
         int parcel_fd = reply.readFileDescriptor();
-        ssize_t size = reply.readInt32();
-        uint32_t flags = reply.readInt32();
-        uint32_t offset = reply.readInt32();
-
-        ALOGE_IF(err, "binder=%p transaction failed fd=%d, size=%zd, err=%d (%s)",
-                IInterface::asBinder(this).get(),
-                parcel_fd, size, err, strerror(-err));
+        const uint64_t size64 = reply.readUint64();
+        const int64_t offset64 = reply.readInt64();
+        const uint32_t flags = reply.readUint32();
+        const size_t size = (size_t)size64;
+        const off_t offset = (off_t)offset64;
+        if (err != NO_ERROR || // failed transaction
+                size != size64 || offset != offset64) { // ILP32 size check
+            ALOGE("binder=%p transaction failed fd=%d, size=%zu, err=%d (%s)",
+                    IInterface::asBinder(this).get(),
+                    parcel_fd, size, err, strerror(-err));
+            return;
+        }
 
         Mutex::Autolock _l(mLock);
         if (mHeapId.load(memory_order_relaxed) == -1) {
             int fd = fcntl(parcel_fd, F_DUPFD_CLOEXEC, 0);
-            ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, err=%d (%s)",
+            ALOGE_IF(fd == -1, "cannot dup fd=%d, size=%zu, err=%d (%s)",
                     parcel_fd, size, err, strerror(errno));
 
             int access = PROT_READ;
@@ -334,7 +345,7 @@
             mRealHeap = true;
             mBase = mmap(nullptr, size, access, MAP_SHARED, fd, offset);
             if (mBase == MAP_FAILED) {
-                ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zd, fd=%d (%s)",
+                ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zu, fd=%d (%s)",
                         IInterface::asBinder(this).get(), size, fd, strerror(errno));
                 close(fd);
             } else {
@@ -368,7 +379,7 @@
     return mFlags;
 }
 
-uint32_t BpMemoryHeap::getOffset() const {
+off_t BpMemoryHeap::getOffset() const {
     assertMapped();
     return mOffset;
 }
@@ -383,6 +394,7 @@
 BnMemoryHeap::~BnMemoryHeap() {
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnMemoryHeap::onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -390,9 +402,9 @@
        case HEAP_ID: {
             CHECK_INTERFACE(IMemoryHeap, data, reply);
             reply->writeFileDescriptor(getHeapID());
-            reply->writeInt32(getSize());
-            reply->writeInt32(getFlags());
-            reply->writeInt32(getOffset());
+            reply->writeUint64(getSize());
+            reply->writeInt64(getOffset());
+            reply->writeUint32(getFlags());
             return NO_ERROR;
         } break;
         default:
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index 89ebc6c..6b99150 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -109,6 +109,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnPermissionController::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp
index 14b5259..159763d 100644
--- a/libs/binder/IResultReceiver.cpp
+++ b/libs/binder/IResultReceiver.cpp
@@ -48,6 +48,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnResultReceiver::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp
index dd4a65e..6c697de 100644
--- a/libs/binder/IShellCallback.cpp
+++ b/libs/binder/IShellCallback.cpp
@@ -58,6 +58,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnShellCallback::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 9850ad9..4c300b4 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -76,7 +76,7 @@
     }
 }
 
-MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset)
+MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, off_t offset)
     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
       mDevice(nullptr), mNeedUnmap(false), mOffset(0)
 {
@@ -85,7 +85,7 @@
     mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), size, offset);
 }
 
-status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
+status_t MemoryHeapBase::init(int fd, void *base, size_t size, int flags, const char* device)
 {
     if (mFD != -1) {
         return INVALID_OPERATION;
@@ -98,13 +98,20 @@
     return NO_ERROR;
 }
 
-status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset)
+status_t MemoryHeapBase::mapfd(int fd, size_t size, off_t offset)
 {
     if (size == 0) {
         // try to figure out the size automatically
         struct stat sb;
-        if (fstat(fd, &sb) == 0)
-            size = sb.st_size;
+        if (fstat(fd, &sb) == 0) {
+            size = (size_t)sb.st_size;
+            // sb.st_size is off_t which on ILP32 may be 64 bits while size_t is 32 bits.
+            if ((off_t)size != sb.st_size) {
+                ALOGE("%s: size of file %lld cannot fit in memory",
+                        __func__, (long long)sb.st_size);
+                return INVALID_OPERATION;
+            }
+        }
         // if it didn't work, let mmap() fail.
     }
 
@@ -112,12 +119,12 @@
         void* base = (uint8_t*)mmap(nullptr, size,
                 PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
         if (base == MAP_FAILED) {
-            ALOGE("mmap(fd=%d, size=%u) failed (%s)",
-                    fd, uint32_t(size), strerror(errno));
+            ALOGE("mmap(fd=%d, size=%zu) failed (%s)",
+                    fd, size, strerror(errno));
             close(fd);
             return -errno;
         }
-        //ALOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
+        //ALOGD("mmap(fd=%d, base=%p, size=%zu)", fd, base, size);
         mBase = base;
         mNeedUnmap = true;
     } else  {
@@ -140,7 +147,7 @@
     int fd = android_atomic_or(-1, &mFD);
     if (fd >= 0) {
         if (mNeedUnmap) {
-            //ALOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
+            //ALOGD("munmap(fd=%d, base=%p, size=%zu)", fd, mBase, mSize);
             munmap(mBase, mSize);
         }
         mBase = nullptr;
@@ -169,7 +176,7 @@
     return mDevice;
 }
 
-uint32_t MemoryHeapBase::getOffset() const {
+off_t MemoryHeapBase::getOffset() const {
     return mOffset;
 }
 
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 0b60b4e..c251468 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -34,15 +34,18 @@
     virtual status_t    pingBinder();
     virtual status_t    dump(int fd, const Vector<String16>& args);
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    transact(   uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
                                     uint32_t flags = 0);
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient,
                                     void* cookie = nullptr,
                                     uint32_t flags = 0);
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    unlinkToDeath(  const wp<DeathRecipient>& recipient,
                                         void* cookie = nullptr,
                                         uint32_t flags = 0,
@@ -60,6 +63,7 @@
 protected:
     virtual             ~BBinder();
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index c4c8ba3..1d4f881 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -41,14 +41,18 @@
     virtual status_t    pingBinder();
     virtual status_t    dump(int fd, const Vector<String16>& args);
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    transact(   uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
                                     uint32_t flags = 0);
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient,
                                     void* cookie = nullptr,
                                     uint32_t flags = 0);
+
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    unlinkToDeath(  const wp<DeathRecipient>& recipient,
                                         void* cookie = nullptr,
                                         uint32_t flags = 0,
diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h
index e5b12a9..b500219 100644
--- a/libs/binder/include/binder/IAppOpsCallback.h
+++ b/libs/binder/include/binder/IAppOpsCallback.h
@@ -43,6 +43,7 @@
 class BnAppOpsCallback : public BnInterface<IAppOpsCallback>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index f0c5e17..7807851 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -67,6 +67,7 @@
 class BnAppOpsService : public BnInterface<IAppOpsService>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h
index 59e806c..48da865 100644
--- a/libs/binder/include/binder/IBatteryStats.h
+++ b/libs/binder/include/binder/IBatteryStats.h
@@ -68,6 +68,7 @@
 class BnBatteryStats : public BnInterface<IBatteryStats>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 3f0dad0..1674516 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -47,7 +47,7 @@
  * (method calls, property get and set) is down through a low-level
  * protocol implemented on top of the transact() API.
  */
-class IBinder : public virtual RefBase
+class [[clang::lto_visibility_public]] IBinder : public virtual RefBase
 {
 public:
     enum {
@@ -86,6 +86,7 @@
                                          Vector<String16>& args, const sp<IShellCallback>& callback,
                                          const sp<IResultReceiver>& resultReceiver);
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t        transact(   uint32_t code,
                                         const Parcel& data,
                                         Parcel* reply,
@@ -131,6 +132,7 @@
      * (Nor should you need to, as there is nothing useful you can
      * directly do with it now that it has passed on.)
      */
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t        linkToDeath(const sp<DeathRecipient>& recipient,
                                         void* cookie = nullptr,
                                         uint32_t flags = 0) = 0;
@@ -142,6 +144,7 @@
      * supply a NULL @a recipient, and the recipient previously
      * added with that cookie will be unlinked.
      */
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t        unlinkToDeath(  const wp<DeathRecipient>& recipient,
                                             void* cookie = nullptr,
                                             uint32_t flags = 0,
diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h
index 3099bf5..071946f 100644
--- a/libs/binder/include/binder/IMemory.h
+++ b/libs/binder/include/binder/IMemory.h
@@ -43,7 +43,7 @@
     virtual void*       getBase() const = 0;
     virtual size_t      getSize() const = 0;
     virtual uint32_t    getFlags() const = 0;
-    virtual uint32_t    getOffset() const = 0;
+    virtual off_t       getOffset() const = 0;
 
     // these are there just for backward source compatibility
     int32_t heapID() const { return getHeapID(); }
@@ -54,7 +54,8 @@
 class BnMemoryHeap : public BnInterface<IMemoryHeap>
 {
 public:
-    virtual status_t onTransact( 
+    // NOLINTNEXTLINE(google-default-arguments)
+    virtual status_t onTransact(
             uint32_t code,
             const Parcel& data,
             Parcel* reply,
@@ -72,6 +73,7 @@
 public:
     DECLARE_META_INTERFACE(Memory)
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const = 0;
 
     // helpers
@@ -84,6 +86,7 @@
 class BnMemory : public BnInterface<IMemory>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t onTransact(
             uint32_t code,
             const Parcel& data,
diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h
index 3ec459f..26a1b23 100644
--- a/libs/binder/include/binder/IPermissionController.h
+++ b/libs/binder/include/binder/IPermissionController.h
@@ -56,6 +56,7 @@
 class BnPermissionController : public BnInterface<IPermissionController>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/IResultReceiver.h b/libs/binder/include/binder/IResultReceiver.h
index e494fba..00b3d89 100644
--- a/libs/binder/include/binder/IResultReceiver.h
+++ b/libs/binder/include/binder/IResultReceiver.h
@@ -41,6 +41,7 @@
 class BnResultReceiver : public BnInterface<IResultReceiver>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 1d39aa3..aeea1a2 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -61,6 +61,7 @@
     /**
      * Register a service.
      */
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t addService(const String16& name, const sp<IBinder>& service,
                                 bool allowIsolated = false,
                                 int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0;
@@ -68,6 +69,7 @@
     /**
      * Return list of all existing services.
      */
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
 
     enum {
diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
index b47e995..6715678 100644
--- a/libs/binder/include/binder/IShellCallback.h
+++ b/libs/binder/include/binder/IShellCallback.h
@@ -42,6 +42,7 @@
 class BnShellCallback : public BnInterface<IShellCallback>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h
index d81789e..9937ad6 100644
--- a/libs/binder/include/binder/IUidObserver.h
+++ b/libs/binder/include/binder/IUidObserver.h
@@ -47,6 +47,7 @@
 class BnUidObserver : public BnInterface<IUidObserver>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t  onTransact(uint32_t code,
                                  const Parcel& data,
                                  Parcel* reply,
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index 5e0a382..2f5039d 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -42,7 +42,7 @@
      * maps the memory referenced by fd. but DOESN'T take ownership
      * of the filedescriptor (it makes a copy with dup()
      */
-    MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, uint32_t offset = 0);
+    MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, off_t offset = 0);
 
     /*
      * maps memory from the given device
@@ -64,7 +64,7 @@
 
     virtual size_t      getSize() const;
     virtual uint32_t    getFlags() const;
-    virtual uint32_t    getOffset() const;
+            off_t       getOffset() const override;
 
     const char*         getDevice() const;
 
@@ -82,11 +82,11 @@
 protected:
             MemoryHeapBase();
     // init() takes ownership of fd
-    status_t init(int fd, void *base, int size,
+    status_t init(int fd, void *base, size_t size,
             int flags = 0, const char* device = nullptr);
 
 private:
-    status_t mapfd(int fd, size_t size, uint32_t offset = 0);
+    status_t mapfd(int fd, size_t size, off_t offset = 0);
 
     int         mFD;
     size_t      mSize;
@@ -94,7 +94,7 @@
     uint32_t    mFlags;
     const char* mDevice;
     bool        mNeedUnmap;
-    uint32_t    mOffset;
+    off_t       mOffset;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/binder/ndk/.clang-format b/libs/binder/ndk/.clang-format
new file mode 100644
index 0000000..9a9d936
--- /dev/null
+++ b/libs/binder/ndk/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: Google
+ColumnLimit: 100
+IndentWidth: 4
+ContinuationIndentWidth: 8
+PointerAlignment: Left
+TabWidth: 4
+AllowShortFunctionsOnASingleLine: Inline
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 5461b4f..d16502f 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -38,6 +38,8 @@
         "libbinder",
         "libutils",
     ],
+
+    version_script: "libbinder_ndk.map.txt",
 }
 
 ndk_headers {
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 896c5c1..f3fb9c3 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -45,7 +45,7 @@
     return binder != nullptr && binder->findObject(kId) == kValue;
 }
 
-} // namespace ABBinderTag
+}  // namespace ABBinderTag
 
 namespace ABpBinderTag {
 
@@ -60,7 +60,7 @@
     delete static_cast<Value*>(obj);
 };
 
-} // namespace ABpBinderTag
+}  // namespace ABpBinderTag
 
 AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
 AIBinder::~AIBinder() {}
@@ -91,7 +91,7 @@
         return false;
     }
 
-    CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor
+    CHECK(asABpBinder() != nullptr);  // ABBinder always has a descriptor
 
     String8 descriptor(getBinder()->getInterfaceDescriptor());
     if (descriptor != newDescriptor) {
@@ -107,7 +107,7 @@
 }
 
 ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData)
-      : AIBinder(clazz), BBinder(), mUserData(userData) {
+    : AIBinder(clazz), BBinder(), mUserData(userData) {
     CHECK(clazz != nullptr);
 }
 ABBinder::~ABBinder() {
@@ -136,7 +136,7 @@
 }
 
 ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder)
-      : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
+    : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
     CHECK(binder != nullptr);
 }
 ABpBinder::~ABpBinder() {}
@@ -214,10 +214,10 @@
 AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
                                AIBinder_Class_onDestroy onDestroy,
                                AIBinder_Class_onTransact onTransact)
-      : onCreate(onCreate),
-        onDestroy(onDestroy),
-        onTransact(onTransact),
-        mInterfaceDescriptor(interfaceDescriptor) {}
+    : onCreate(onCreate),
+      onDestroy(onDestroy),
+      onTransact(onTransact),
+      mInterfaceDescriptor(interfaceDescriptor) {}
 
 AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
                                       AIBinder_Class_onCreate onCreate,
@@ -239,7 +239,7 @@
 }
 
 AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied)
-      : mOnDied(onDied) {
+    : mOnDied(onDied) {
     CHECK(onDied != nullptr);
 }
 
@@ -302,7 +302,7 @@
 
 bool AIBinder_isRemote(const AIBinder* binder) {
     if (binder == nullptr) {
-        return true;
+        return false;
     }
 
     return binder->isRemote();
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 5b6bc94..ac592ea 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -49,7 +49,7 @@
         return binder->remoteBinder() != nullptr;
     }
 
-private:
+   private:
     // AIBinder instance is instance of this class for a local object. In order to transact on a
     // remote object, this also must be set for simplicity (although right now, only the
     // interfaceDescriptor from it is used).
@@ -69,7 +69,7 @@
     ::android::status_t onTransact(uint32_t code, const ::android::Parcel& data,
                                    ::android::Parcel* reply, binder_flags_t flags) override;
 
-private:
+   private:
     ABBinder(const AIBinder_Class* clazz, void* userData);
 
     // only thing that should create an ABBinder
@@ -96,7 +96,7 @@
     ::android::sp<::android::IBinder> getBinder() override { return remote(); }
     ABpBinder* asABpBinder() override { return this; }
 
-private:
+   private:
     ABpBinder(const ::android::sp<::android::IBinder>& binder);
 };
 
@@ -110,7 +110,7 @@
     const AIBinder_Class_onDestroy onDestroy;
     const AIBinder_Class_onTransact onTransact;
 
-private:
+   private:
     // This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
     // one.
     const ::android::String16 mInterfaceDescriptor;
@@ -128,14 +128,14 @@
     struct TransferDeathRecipient : ::android::IBinder::DeathRecipient {
         TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie,
                                const AIBinder_DeathRecipient_onBinderDied& onDied)
-              : mWho(who), mCookie(cookie), mOnDied(onDied) {}
+            : mWho(who), mCookie(cookie), mOnDied(onDied) {}
 
         void binderDied(const ::android::wp<::android::IBinder>& who) override;
 
         const ::android::wp<::android::IBinder>& getWho() { return mWho; }
         void* getCookie() { return mCookie; }
 
-    private:
+       private:
         ::android::wp<::android::IBinder> mWho;
         void* mCookie;
         const AIBinder_DeathRecipient_onBinderDied& mOnDied;
@@ -145,7 +145,7 @@
     binder_status_t linkToDeath(AIBinder* binder, void* cookie);
     binder_status_t unlinkToDeath(AIBinder* binder, void* cookie);
 
-private:
+   private:
     std::mutex mDeathRecipientsMutex;
     std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients;
     AIBinder_DeathRecipient_onBinderDied mOnDied;
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_apex/android/binder_manager.h
index b8f38ba..80b6c07 100644
--- a/libs/binder/ndk/include_apex/android/binder_manager.h
+++ b/libs/binder/ndk/include_apex/android/binder_manager.h
@@ -17,11 +17,18 @@
 #pragma once
 
 #include <android/binder_ibinder.h>
+#include <android/binder_status.h>
 
 __BEGIN_DECLS
 
 /**
- * This registers the service with the default service manager under this instance name.
+ * This registers the service with the default service manager under this instance name. This does
+ * not take ownership of binder.
+ *
+ * \param binder object to register globally with the service manager.
+ * \param instance identifier of the service. This will be used to lookup the service.
+ *
+ * \return STATUS_OK on success.
  */
 binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance);
 
@@ -29,6 +36,8 @@
  * Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
  * it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
  * for calling AIBinder_decStrong).
+ *
+ * \param instance identifier of the service used to lookup the service.
  */
 __attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
 
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index cc0a29d..5c26039 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -32,8 +32,7 @@
 
 #include <assert.h>
 
-#ifdef __cplusplus
-
+#include <unistd.h>
 #include <cstddef>
 
 namespace ndk {
@@ -42,7 +41,7 @@
  * Represents one strong pointer to an AIBinder object.
  */
 class SpAIBinder {
-public:
+   public:
     /**
      * Takes ownership of one strong refcount of binder.
      */
@@ -106,30 +105,30 @@
      */
     AIBinder** getR() { return &mBinder; }
 
-private:
+   private:
     AIBinder* mBinder = nullptr;
 };
 
 /**
  * This baseclass owns a single object, used to make various classes RAII.
  */
-template <typename T, void (*Destroy)(T*)>
+template <typename T, typename R, R (*Destroy)(T), T DEFAULT>
 class ScopedAResource {
-public:
+   public:
     /**
      * Takes ownership of t.
      */
-    explicit ScopedAResource(T* t = nullptr) : mT(t) {}
+    explicit ScopedAResource(T t = DEFAULT) : mT(t) {}
 
     /**
      * This deletes the underlying object if it exists. See set.
      */
-    ~ScopedAResource() { set(nullptr); }
+    ~ScopedAResource() { set(DEFAULT); }
 
     /**
      * Takes ownership of t.
      */
-    void set(T* t) {
+    void set(T t) {
         Destroy(mT);
         mT = t;
     }
@@ -137,12 +136,12 @@
     /**
      * This returns the underlying object to be modified but does not affect ownership.
      */
-    T* get() { return mT; }
+    T get() { return mT; }
 
     /**
      * This returns the const underlying object but does not affect ownership.
      */
-    const T* get() const { return mT; }
+    const T get() const { return mT; }
 
     /**
      * This allows the value in this class to be set from beneath it. If you call this method and
@@ -156,7 +155,7 @@
      * Other usecases are discouraged.
      *
      */
-    T** getR() { return &mT; }
+    T* getR() { return &mT; }
 
     // copy-constructing, or move/copy assignment is disallowed
     ScopedAResource(const ScopedAResource&) = delete;
@@ -166,15 +165,15 @@
     // move-constructing is okay
     ScopedAResource(ScopedAResource&&) = default;
 
-private:
-    T* mT;
+   private:
+    T mT;
 };
 
 /**
  * Convenience wrapper. See AParcel.
  */
-class ScopedAParcel : public ScopedAResource<AParcel, AParcel_delete> {
-public:
+class ScopedAParcel : public ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
+   public:
     /**
      * Takes ownership of a.
      */
@@ -186,8 +185,8 @@
 /**
  * Convenience wrapper. See AStatus.
  */
-class ScopedAStatus : public ScopedAResource<AStatus, AStatus_delete> {
-public:
+class ScopedAStatus : public ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
+   public:
     /**
      * Takes ownership of a.
      */
@@ -205,13 +204,14 @@
  * Convenience wrapper. See AIBinder_DeathRecipient.
  */
 class ScopedAIBinder_DeathRecipient
-      : public ScopedAResource<AIBinder_DeathRecipient, AIBinder_DeathRecipient_delete> {
-public:
+    : public ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
+                             nullptr> {
+   public:
     /**
      * Takes ownership of a.
      */
     explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr)
-          : ScopedAResource(a) {}
+        : ScopedAResource(a) {}
     ~ScopedAIBinder_DeathRecipient() {}
     ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default;
 };
@@ -219,8 +219,9 @@
 /**
  * Convenience wrapper. See AIBinder_Weak.
  */
-class ScopedAIBinder_Weak : public ScopedAResource<AIBinder_Weak, AIBinder_Weak_delete> {
-public:
+class ScopedAIBinder_Weak
+    : public ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
+   public:
     /**
      * Takes ownership of a.
      */
@@ -234,8 +235,19 @@
     SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
 };
 
-} // namespace ndk
+/**
+ * Convenience wrapper for a file descriptor.
+ */
+class ScopedFileDescriptor : public ScopedAResource<int, int, close, -1> {
+   public:
+    /**
+     * Takes ownership of a.
+     */
+    explicit ScopedFileDescriptor(int a = -1) : ScopedAResource(a) {}
+    ~ScopedFileDescriptor() {}
+    ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
+};
 
-#endif // __cplusplus
+}  // namespace ndk
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index c222c16..d711ad8 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -126,8 +126,9 @@
 /**
  * This is called whenever a new AIBinder object is needed of a specific class.
  *
- * These arguments are passed from AIBinder_new. The return value is stored and can be retrieved
- * using AIBinder_getUserData.
+ * \param args these can be used to construct a new class. These are passed from AIBinder_new.
+ * \return this is the userdata representing the class. It can be retrieved using
+ * AIBinder_getUserData.
  */
 typedef void* (*AIBinder_Class_onCreate)(void* args);
 
@@ -135,23 +136,41 @@
  * This is called whenever an AIBinder object is no longer referenced and needs destroyed.
  *
  * Typically, this just deletes whatever the implementation is.
+ *
+ * \param userData this is the same object returned by AIBinder_Class_onCreate
  */
 typedef void (*AIBinder_Class_onDestroy)(void* userData);
 
 /**
  * This is called whenever a transaction needs to be processed by a local implementation.
+ *
+ * \param binder the object being transacted on.
+ * \param code implementation-specific code representing which transaction should be taken.
+ * \param in the implementation-specific input data to this transaction.
+ * \param out the implementation-specific output data to this transaction.
+ *
+ * \return the implementation-specific output code. This may be forwarded from another service, the
+ * result of a parcel read or write, or another error as is applicable to the specific
+ * implementation. Usually, implementation-specific error codes are written to the output parcel,
+ * and the transaction code is reserved for kernel errors or error codes that have been repeated
+ * from subsequent transactions.
  */
 typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, transaction_code_t code,
                                                      const AParcel* in, AParcel* out);
 
 /**
- * An interfaceDescriptor uniquely identifies the type of object that is being created. This is used
- * internally for sanity checks on transactions.
+ * This creates a new instance of a class of binders which can be instantiated. This is called one
+ * time during library initialization and cleaned up when the process exits or execs.
  *
- * None of these parameters can be nullptr.
+ * None of these parameters can be null.
  *
- * This is created one time during library initialization and cleaned up when the process exits or
- * execs.
+ * \param interfaceDescriptor this is a unique identifier for the class. This is used internally for
+ * sanity checks on transactions.
+ * \param onCreate see AIBinder_Class_onCreate.
+ * \param onDestroy see AIBinder_Class_onDestroy.
+ * \param onTransact see AIBinder_Class_onTransact.
+ *
+ * \return the class object representing these parameters or null on error.
  */
 __attribute__((warn_unused_result)) AIBinder_Class* AIBinder_Class_define(
         const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
@@ -174,12 +193,21 @@
  * hypothetical removeCallback function, the remote process would have no way to determine that
  * these two objects are actually equal using the AIBinder pointer alone (which they should be able
  * to do). Also see the suggested memory ownership model suggested above.
+ *
+ * \param clazz the type of the object to be created.
+ * \param args the args to pass to AIBinder_onCreate for that class.
+ *
+ * \return a binder object representing the newly instantiated object.
  */
 __attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args)
         __INTRODUCED_IN(29);
 
 /**
  * If this is hosted in a process other than the current one.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return true if the AIBinder represents an object in another process.
  */
 bool AIBinder_isRemote(const AIBinder* binder) __INTRODUCED_IN(29);
 
@@ -189,13 +217,21 @@
  * this is automatically updated to reflect the current alive status of this binder. This will be
  * updated as the result of a transaction made using AIBinder_transact, but it will also be updated
  * based on the results of bookkeeping or other transactions made internally.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return true if the binder is alive.
  */
 bool AIBinder_isAlive(const AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
- * Built-in transaction for all binder objects. This sends a transaction which will immediately
+ * Built-in transaction for all binder objects. This sends a transaction that will immediately
  * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a
  * sanity check.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return STATUS_OK if the ping succeeds.
  */
 binder_status_t AIBinder_ping(AIBinder* binder) __INTRODUCED_IN(29);
 
@@ -209,6 +245,12 @@
  * identification and holding user data.
  *
  * If binder is local, this will return STATUS_INVALID_OPERATION.
+ *
+ * \param binder the binder object you want to receive death notifications from.
+ * \param recipient the callback that will receive notifications when/if the binder dies.
+ * \param cookie the value that will be passed to the death recipient on death.
+ *
+ * \return STATUS_OK on success.
  */
 binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                      void* cookie) __INTRODUCED_IN(29);
@@ -217,22 +259,37 @@
  * Stops registration for the associated binder dying. Does not delete the recipient. This function
  * may return a binder transaction failure and in case the death recipient cannot be found, it
  * returns STATUS_NAME_NOT_FOUND.
+ *
+ * \param binder the binder object to remove a previously linked death recipient from.
+ * \param recipient the callback to remove.
+ * \param cookie the cookie used to link to death.
+ *
+ * \return STATUS_OK on success. STATUS_NAME_NOT_FOUND if the binder cannot be found to be unlinked.
  */
 binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                        void* cookie) __INTRODUCED_IN(29);
 
 /**
  * This can only be called if a strong reference to this object already exists in process.
+ *
+ * \param binder the binder object to add a refcount to.
  */
 void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * This will delete the object and call onDestroy once the refcount reaches zero.
+ *
+ * \param binder the binder object to remove a refcount from.
  */
 void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * For debugging only!
+ *
+ * \param binder the binder object to retrieve the refcount of.
+ *
+ * \return the number of strong-refs on this binder in this process. If binder is null, this will be
+ * -1.
  */
 int32_t AIBinder_debugGetRefCount(AIBinder* binder) __INTRODUCED_IN(29);
 
@@ -244,17 +301,32 @@
  *
  * This returns true if the class association succeeds. If it fails, no change is made to the
  * binder object.
+ *
+ * \param binder the object to attach the class to.
+ * \param clazz the clazz to attach to binder.
+ *
+ * \return true if the binder has the class clazz and if the association was successful.
  */
 bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) __INTRODUCED_IN(29);
 
 /**
  * Returns the class that this binder was constructed with or associated with.
+ *
+ * \param binder the object that is being queried.
+ *
+ * \return the class that this binder is associated with. If this binder wasn't created with
+ * AIBinder_new, and AIBinder_associateClass hasn't been called, then this will return null.
  */
 const AIBinder_Class* AIBinder_getClass(AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * Value returned by onCreate for a local binder. For stateless classes (if onCreate returns
- * nullptr), this also returns nullptr. For a remote binder, this will always return nullptr.
+ * null), this also returns null. For a remote binder, this will always return null.
+ *
+ * \param binder the object that is being queried.
+ *
+ * \return the userdata returned from AIBinder_onCreate when this object was created. This may be
+ * null for stateless objects. For remote objects, this is always null.
  */
 void* AIBinder_getUserData(AIBinder* binder) __INTRODUCED_IN(29);
 
@@ -278,6 +350,12 @@
  * ownership is passed to the caller. At this point, the parcel can be filled out and passed to
  * AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be
  * deleted with AParcel_delete.
+ *
+ * \param binder the binder object to start a transaction on.
+ * \param in out parameter for input data to the transaction.
+ *
+ * \return STATUS_OK on success. This will return STATUS_INVALID_OPERATION if the binder has not yet
+ * been associated with a class (see AIBinder_new and AIBinder_associateClass).
  */
 binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) __INTRODUCED_IN(29);
 
@@ -292,6 +370,16 @@
  *
  * This does not affect the ownership of binder. The out parcel's ownership is passed to the caller
  * and must be released with AParcel_delete when finished reading.
+ *
+ * \param binder the binder object to transact on.
+ * \param code the implementation-specific code representing which transaction should be taken.
+ * \param in the implementation-specific input data to this transaction.
+ * \param out the implementation-specific output data to this transaction.
+ * \param flags possible flags to alter the way in which the transaction is conducted or 0.
+ *
+ * \return the result from the kernel or from the remote process. Usually, implementation-specific
+ * error codes are written to the output parcel, and the transaction code is reserved for kernel
+ * errors or error codes that have been repeated from subsequent transactions.
  */
 binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
                                   AParcel** out, binder_flags_t flags) __INTRODUCED_IN(29);
@@ -299,29 +387,45 @@
 /**
  * This does not take any ownership of the input binder, but it can be used to retrieve it if
  * something else in some process still holds a reference to it.
+ *
+ * \param binder object to create a weak pointer to.
+ *
+ * \return object representing a weak pointer to binder (or null if binder is null).
  */
 __attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder)
         __INTRODUCED_IN(29);
 
 /**
  * Deletes the weak reference. This will have no impact on the lifetime of the binder.
+ *
+ * \param weakBinder object created with AIBinder_Weak_new.
  */
 void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29);
 
 /**
  * If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns
- * nullptr.
+ * null.
+ *
+ * \param weakBinder weak pointer to attempt retrieving the original object from.
+ *
+ * \return an AIBinder object with one refcount given to the caller or null.
  */
 __attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder)
         __INTRODUCED_IN(29);
 
 /**
  * This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
+ *
+ * \param cookie the cookie passed to AIBinder_linkToDeath.
  */
 typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29);
 
 /**
  * Creates a new binder death recipient. This can be attached to multiple different binder objects.
+ *
+ * \param onBinderDied the callback to call when this death recipient is invoked.
+ *
+ * \return the newly constructed object (or null if onBinderDied is null).
  */
 __attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
         AIBinder_DeathRecipient_onBinderDied onBinderDied) __INTRODUCED_IN(29);
@@ -329,10 +433,12 @@
 /**
  * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
  * calling this as these will all be automatically unlinked.
+ *
+ * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new).
  */
 void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29);
 
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
index 81fb3c5..124f36c 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -39,6 +39,12 @@
  * If either env or the binder is null, null is returned. If this binder object was originally an
  * AIBinder object, the original object is returned. The returned object has one refcount
  * associated with it, and so this should be accompanied with an AIBinder_decStrong call.
+ *
+ * \param env Java environment.
+ * \param binder android.os.IBinder java object.
+ *
+ * \return an AIBinder object representing the Java binder object. If either parameter is null, or
+ * the Java object is of the wrong type, this will return null.
  */
 __attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder)
         __INTRODUCED_IN(29);
@@ -48,11 +54,16 @@
  *
  * If either env or the binder is null, null is returned. If this binder object was originally an
  * IBinder object, the original java object will be returned.
+ *
+ * \param env Java environment.
+ * \param binder the object to convert.
+ *
+ * \return an android.os.IBinder object or null if the parameters were null.
  */
 __attribute__((warn_unused_result)) jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder)
         __INTRODUCED_IN(29);
 
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
index e37c388..1532725 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -32,8 +32,6 @@
 
 #include <assert.h>
 
-#ifdef __cplusplus
-
 #include <memory>
 #include <mutex>
 
@@ -46,7 +44,7 @@
  * construct this object is with SharedRefBase::make.
  */
 class SharedRefBase {
-public:
+   public:
     SharedRefBase() {}
     virtual ~SharedRefBase() {
         std::call_once(mFlagThis, [&]() {
@@ -83,7 +81,7 @@
         return t->template ref<T>();
     }
 
-private:
+   private:
     std::once_flag mFlagThis;
     std::weak_ptr<SharedRefBase> mThis;
 };
@@ -92,7 +90,7 @@
  * wrapper analog to IInterface
  */
 class ICInterface : public SharedRefBase {
-public:
+   public:
     ICInterface() {}
     virtual ~ICInterface() {}
 
@@ -113,7 +111,7 @@
  */
 template <typename INTERFACE>
 class BnCInterface : public INTERFACE {
-public:
+   public:
     BnCInterface() {}
     virtual ~BnCInterface() {}
 
@@ -121,15 +119,15 @@
 
     bool isRemote() override { return true; }
 
-protected:
+   protected:
     /**
      * This function should only be called by asBinder. Otherwise, there is a possibility of
      * multiple AIBinder* objects being created for the same instance of an object.
      */
     virtual SpAIBinder createBinder() = 0;
 
-private:
-    std::mutex mMutex; // for asBinder
+   private:
+    std::mutex mMutex;  // for asBinder
     ScopedAIBinder_Weak mWeakBinder;
 };
 
@@ -138,7 +136,7 @@
  */
 template <typename INTERFACE>
 class BpCInterface : public INTERFACE {
-public:
+   public:
     BpCInterface(const SpAIBinder& binder) : mBinder(binder) {}
     virtual ~BpCInterface() {}
 
@@ -146,7 +144,7 @@
 
     bool isRemote() override { return AIBinder_isRemote(mBinder.get()); }
 
-private:
+   private:
     SpAIBinder mBinder;
 };
 
@@ -171,8 +169,6 @@
     return mBinder;
 }
 
-} // namespace ndk
-
-#endif // __cplusplus
+}  // namespace ndk
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index d36b3c0..4ee1b67 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -47,110 +47,264 @@
 
 /**
  * Cleans up a parcel.
+ *
+ * \param parcel A parcel returned by AIBinder_prepareTransaction or AIBinder_transact when a
+ * transaction is being aborted.
  */
 void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29);
 
 /**
- * This is called to allocate an array with a given length. If allocation fails, null should be
- * returned.
+ * This is called to allocate a buffer for a C-style string (null-terminated). The returned buffer
+ * should be at least length bytes. This includes space for a null terminator. length will always be
+ * strictly less than or equal to the maximum size that can be held in a size_t and will always be
+ * greater than 0.
+ *
+ * See also AParcel_readString.
+ *
+ * If allocation fails, null should be returned.
+ *
+ * \param stringData some external representation of a string
+ * \param length the length of the buffer needed to fill (including the null-terminator)
+ *
+ * \return a buffer of size 'length' or null if allocation failed.
  */
-typedef void* (*AParcel_arrayReallocator)(void* vectorData, size_t length);
+typedef char* (*AParcel_stringAllocator)(void* stringData, size_t length);
+
+/**
+ * This is called to allocate an array of size 'length'.
+ *
+ * See also AParcel_readStringArray
+ *
+ * \param arrayData some external representation of an array
+ * \param length the length to allocate this array to
+ *
+ * \return true if allocation succeeded
+ */
+typedef bool (*AParcel_stringArrayAllocator)(void* arrayData, size_t length);
+
+/**
+ * This is called to allocate a string inside of an array that was allocated by an
+ * AParcel_stringArrayAllocator.
+ *
+ * The index returned will always be within the range [0, length of arrayData). The returned buffer
+ * should be at least length bytes. This includes space for a null-terminator. length will always be
+ * strictly less than or equal to the maximum size that can be held in a size_t and will always be
+ * greater than 0.
+ *
+ * See also AParcel_readStringArray
+ *
+ * \param arrayData some external representation of an array.
+ * \param index the index at which a string should be allocated.
+ * \param length the length of the string to be allocated at this index. See also
+ * AParcel_stringAllocator. This includes the length required for a null-terminator.
+ *
+ * \return a buffer of size 'length' or null if allocation failed.
+ */
+typedef char* (*AParcel_stringArrayElementAllocator)(void* arrayData, size_t index, size_t length);
+
+/**
+ * This returns the length and buffer of an array at a specific index in an arrayData object.
+ *
+ * See also AParcel_writeStringArray
+ *
+ * \param arrayData some external representation of an array.
+ * \param index the index at which a string should be allocated.
+ * \param outLength an out parameter for the length of the string at the specified index. This
+ * should not include the length for a null-terminator if there is one.
+ *
+ * \param a buffer of size outLength or more representing the string at the provided index. This is
+ * not required to be null-terminated.
+ */
+typedef const char* (*AParcel_stringArrayElementGetter)(const void* arrayData, size_t index,
+                                                        size_t* outLength);
 
 // @START-PRIMITIVE-VECTOR-GETTERS
 /**
  * This is called to get the underlying data from an arrayData object.
  *
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readInt32Array
+ *
+ * \param arrayData some external representation of an array of int32_t.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of int32_t of size 'length'.
  */
-typedef int32_t* (*AParcel_int32ArrayGetter)(void* arrayData);
+typedef int32_t* (*AParcel_int32ArrayAllocator)(void* arrayData, size_t length);
 
 /**
  * This is called to get the underlying data from an arrayData object.
  *
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readUint32Array
+ *
+ * \param arrayData some external representation of an array of uint32_t.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of uint32_t of size 'length'.
  */
-typedef uint32_t* (*AParcel_uint32ArrayGetter)(void* arrayData);
+typedef uint32_t* (*AParcel_uint32ArrayAllocator)(void* arrayData, size_t length);
 
 /**
  * This is called to get the underlying data from an arrayData object.
  *
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readInt64Array
+ *
+ * \param arrayData some external representation of an array of int64_t.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of int64_t of size 'length'.
  */
-typedef int64_t* (*AParcel_int64ArrayGetter)(void* arrayData);
+typedef int64_t* (*AParcel_int64ArrayAllocator)(void* arrayData, size_t length);
 
 /**
  * This is called to get the underlying data from an arrayData object.
  *
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readUint64Array
+ *
+ * \param arrayData some external representation of an array of uint64_t.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of uint64_t of size 'length'.
  */
-typedef uint64_t* (*AParcel_uint64ArrayGetter)(void* arrayData);
+typedef uint64_t* (*AParcel_uint64ArrayAllocator)(void* arrayData, size_t length);
 
 /**
  * This is called to get the underlying data from an arrayData object.
  *
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readFloatArray
+ *
+ * \param arrayData some external representation of an array of float.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of float of size 'length'.
  */
-typedef float* (*AParcel_floatArrayGetter)(void* arrayData);
+typedef float* (*AParcel_floatArrayAllocator)(void* arrayData, size_t length);
 
 /**
  * This is called to get the underlying data from an arrayData object.
  *
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readDoubleArray
+ *
+ * \param arrayData some external representation of an array of double.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of double of size 'length'.
  */
-typedef double* (*AParcel_doubleArrayGetter)(void* arrayData);
+typedef double* (*AParcel_doubleArrayAllocator)(void* arrayData, size_t length);
 
 /**
- * This is called to get the underlying data from an arrayData object.
+ * This allocates an array of size 'length' inside of arrayData and returns whether or not there was
+ * a success.
  *
- * This will never be called for an empty array.
+ * See also AParcel_readBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return whether the allocation succeeded.
+ */
+typedef bool (*AParcel_boolArrayAllocator)(void* arrayData, size_t length);
+
+/**
+ * This is called to get the underlying data from an arrayData object at index.
+ *
+ * See also AParcel_writeBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param index the index of the value to be retrieved.
+ *
+ * \return the value of the array at index index.
  */
 typedef bool (*AParcel_boolArrayGetter)(const void* arrayData, size_t index);
 
 /**
  * This is called to set an underlying value in an arrayData object at index.
+ *
+ * See also AParcel_readBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param index the index of the value to be set.
+ * \param value the value to set at index index.
  */
 typedef void (*AParcel_boolArraySetter)(void* arrayData, size_t index, bool value);
 
 /**
  * This is called to get the underlying data from an arrayData object.
  *
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readCharArray
+ *
+ * \param arrayData some external representation of an array of char16_t.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of char16_t of size 'length'.
  */
-typedef char16_t* (*AParcel_charArrayGetter)(void* arrayData);
+typedef char16_t* (*AParcel_charArrayAllocator)(void* arrayData, size_t length);
 
 /**
  * This is called to get the underlying data from an arrayData object.
  *
- * This will never be called for an empty array.
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned.
+ *
+ * See also AParcel_readByteArray
+ *
+ * \param arrayData some external representation of an array of int8_t.
+ * \param length the length to allocate arrayData to.
+ *
+ * \return a buffer of int8_t of size 'length'.
  */
-typedef int8_t* (*AParcel_byteArrayGetter)(void* arrayData);
+typedef int8_t* (*AParcel_byteArrayAllocator)(void* arrayData, size_t length);
 
 // @END-PRIMITIVE-VECTOR-GETTERS
 
 /**
- * This is called to allocate a buffer
+ * Writes an AIBinder to the next location in a non-null parcel. Can be null. This does not take any
+ * refcounts of ownership of the binder from the client.
  *
- * The length here includes the space required to insert a '\0' for a properly formed c-str. If the
- * buffer returned from this function is retStr, it will be filled by AParcel_readString with the
- * data from the remote process, and it will be filled such that retStr[length] == '\0'.
+ * \param parcel the parcel to write to.
+ * \param binder the value to write to the parcel.
  *
- * If allocation fails, null should be returned.
- */
-typedef void* (*AParcel_stringReallocator)(void* stringData, size_t length);
-
-/**
- * This is called to get the buffer from a stringData object.
- */
-typedef char* (*AParcel_stringGetter)(void* stringData);
-
-/**
- * Writes an AIBinder to the next location in a non-null parcel. Can be null.
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * Reads an AIBinder from the next location in a non-null parcel. This will fail if the binder is
  * non-null. One strong ref-count of ownership is passed to the caller of this function.
+ *
+ * \param parcel the parcel to read from.
+ * \param binder the out parameter for what is read from the parcel. This will not be null on
+ * success.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder)
         __INTRODUCED_IN(29);
@@ -158,11 +312,44 @@
 /**
  * Reads an AIBinder from the next location in a non-null parcel. This may read a null. One strong
  * ref-count of ownership is passed to the caller of this function.
+ *
+ * \param parcel the parcel to read from.
+ * \param binder the out parameter for what is read from the parcel. This may be null even on
+ * success.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder)
         __INTRODUCED_IN(29);
 
 /**
+ * Writes a file descriptor to the next location in a non-null parcel. This does not take ownership
+ * of fd.
+ *
+ * This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ *
+ * \param parcel the parcel to write to.
+ * \param fd the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd);
+
+/**
+ * Reads an int from the next location in a non-null parcel.
+ *
+ * The returned fd must be closed.
+ *
+ * This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ *
+ * \param parcel the parcel to read from.
+ * \param binder the out parameter for what is read from the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd);
+
+/**
  * Writes an AStatus object to the next location in a non-null parcel.
  *
  * If the status is considered to be a low-level status and has no additional information other
@@ -170,6 +357,11 @@
  * status will be returned from this method and nothing will be written to the parcel. If either
  * this happens or if writing the status object itself fails, the return value from this function
  * should be propagated to the client, and AParcel_readStatusHeader shouldn't be called.
+ *
+ * \param parcel the parcel to write to.
+ * \param status the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status)
         __INTRODUCED_IN(29);
@@ -177,243 +369,527 @@
 /**
  * Reads an AStatus from the next location in a non-null parcel. Ownership is passed to the caller
  * of this function.
+ *
+ * \param parcel the parcel to read from.
+ * \param status the out parameter for what is read from the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status)
         __INTRODUCED_IN(29);
 
 /**
- * Writes string value to the next location in a non-null parcel.
+ * Writes utf-8 string value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param string the null-terminated string to write to the parcel, at least of size 'length'.
+ * \param length the length of the string to be written.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length)
         __INTRODUCED_IN(29);
 
 /**
- * Reads and allocates string value from the next location in a non-null parcel.
+ * Reads and allocates utf-8 string value from the next location in a non-null parcel.
  *
- * Data is passed to the string allocator once the string size is known. This data should be used to
- * point to some kind of string data. For instance, it could be a char*, and the string allocator
- * could be realloc. Then the getter would simply be a cast to char*. In more complicated cases,
- * stringData could be a structure containing additional string data.
+ * Data is passed to the string allocator once the string size is known. This size includes the
+ * space for the null-terminator of this string. This allocator returns a buffer which is used as
+ * the output buffer from this read.
  *
- * If this function returns a success, the buffer returned by allocator when passed stringData will
- * contain a null-terminated c-str read from the binder.
+ * \param parcel the parcel to read from.
+ * \param stringData some external representation of a string.
+ * \param allocator allocator that will be called once the size of the string is known.
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringReallocator reallocator,
-                                   AParcel_stringGetter getter, void** stringData)
+binder_status_t AParcel_readString(const AParcel* parcel, void* stringData,
+                                   AParcel_stringAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Writes utf-8 string array data to the next location in a non-null parcel.
+ *
+ * length is the length of the array. AParcel_stringArrayElementGetter will be called for all
+ * indices in range [0, length) with the arrayData provided here. The string length and buffer
+ * returned from this function will be used to fill out the data from the parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData some external representation of an array.
+ * \param length the length of the array to be written.
+ * \param getter the callback that will be called for every index of the array to retrieve the
+ * corresponding string buffer.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, size_t length,
+                                         AParcel_stringArrayElementGetter getter)
+        __INTRODUCED_IN(29);
+
+/**
+ * Reads and allocates utf-8 string array value from the next location in a non-null parcel.
+ *
+ * First, AParcel_stringArrayAllocator will be called with the size of the array to be read where
+ * length is the length of the array to be read from the parcel. Then, for each index i in [0,
+ * length), AParcel_stringArrayElementAllocator will be called with the length of the string to be
+ * read from the parcel. The resultant buffer from each of these calls will be filled according to
+ * the contents of the string that is read.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called with arrayData once the size of the output
+ * array is known.
+ * \param elementAllocator the callback that will be called on every index of arrayData to allocate
+ * the string at that location.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData,
+                                        AParcel_stringArrayAllocator allocator,
+                                        AParcel_stringArrayElementAllocator elementAllocator)
         __INTRODUCED_IN(29);
 
 // @START-PRIMITIVE-READ-WRITE
 /**
  * Writes int32_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes uint32_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes int64_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes uint64_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes float value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeFloat(AParcel* parcel, float value) __INTRODUCED_IN(29);
 
 /**
  * Writes double value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeDouble(AParcel* parcel, double value) __INTRODUCED_IN(29);
 
 /**
  * Writes bool value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeBool(AParcel* parcel, bool value) __INTRODUCED_IN(29);
 
 /**
  * Writes char16_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes int8_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value) __INTRODUCED_IN(29);
 
 /**
  * Reads into int32_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into uint32_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into int64_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into uint64_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into float value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readFloat(const AParcel* parcel, float* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into double value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readDouble(const AParcel* parcel, double* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into bool value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readBool(const AParcel* parcel, bool* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into char16_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into int8_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) __INTRODUCED_IN(29);
 
 /**
  * Writes an array of int32_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* value, size_t length)
+binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, size_t length)
         __INTRODUCED_IN(29);
 
 /**
  * Writes an array of uint32_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* value, size_t length)
+binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData, size_t length)
         __INTRODUCED_IN(29);
 
 /**
  * Writes an array of int64_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* value, size_t length)
+binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, size_t length)
         __INTRODUCED_IN(29);
 
 /**
  * Writes an array of uint64_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* value, size_t length)
+binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData, size_t length)
         __INTRODUCED_IN(29);
 
 /**
  * Writes an array of float to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* value, size_t length)
+binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, size_t length)
         __INTRODUCED_IN(29);
 
 /**
  * Writes an array of double to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* value, size_t length)
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, size_t length)
         __INTRODUCED_IN(29);
 
 /**
  * Writes an array of bool to the next location in a non-null parcel.
+ *
+ * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying
+ * values to write to the parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData some external representation of an array.
+ * \param length the length of arrayData.
+ * \param getter the callback to retrieve data at specific locations in the array.
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData,
-                                       AParcel_boolArrayGetter getter, size_t length)
-        __INTRODUCED_IN(29);
+binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, size_t length,
+                                       AParcel_boolArrayGetter getter) __INTRODUCED_IN(29);
 
 /**
  * Writes an array of char16_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* value, size_t length)
+binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, size_t length)
         __INTRODUCED_IN(29);
 
 /**
  * Writes an array of int8_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length'.
+ * \param length the length of arrayData.
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* value, size_t length)
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, size_t length)
         __INTRODUCED_IN(29);
 
 /**
  * Reads an array of int32_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
  */
-binder_status_t AParcel_readInt32Array(const AParcel* parcel, void** arrayData,
-                                       AParcel_arrayReallocator reallocator,
-                                       AParcel_int32ArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData,
+                                       AParcel_int32ArrayAllocator allocator) __INTRODUCED_IN(29);
 
 /**
  * Reads an array of uint32_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
  */
-binder_status_t AParcel_readUint32Array(const AParcel* parcel, void** arrayData,
-                                        AParcel_arrayReallocator reallocator,
-                                        AParcel_uint32ArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData,
+                                        AParcel_uint32ArrayAllocator allocator) __INTRODUCED_IN(29);
 
 /**
  * Reads an array of int64_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
  */
-binder_status_t AParcel_readInt64Array(const AParcel* parcel, void** arrayData,
-                                       AParcel_arrayReallocator reallocator,
-                                       AParcel_int64ArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData,
+                                       AParcel_int64ArrayAllocator allocator) __INTRODUCED_IN(29);
 
 /**
  * Reads an array of uint64_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
  */
-binder_status_t AParcel_readUint64Array(const AParcel* parcel, void** arrayData,
-                                        AParcel_arrayReallocator reallocator,
-                                        AParcel_uint64ArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData,
+                                        AParcel_uint64ArrayAllocator allocator) __INTRODUCED_IN(29);
 
 /**
  * Reads an array of float from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
  */
-binder_status_t AParcel_readFloatArray(const AParcel* parcel, void** arrayData,
-                                       AParcel_arrayReallocator reallocator,
-                                       AParcel_floatArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData,
+                                       AParcel_floatArrayAllocator allocator) __INTRODUCED_IN(29);
 
 /**
  * Reads an array of double from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
  */
-binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void** arrayData,
-                                        AParcel_arrayReallocator reallocator,
-                                        AParcel_doubleArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData,
+                                        AParcel_doubleArrayAllocator allocator) __INTRODUCED_IN(29);
 
 /**
  * Reads an array of bool from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. Then, for every i in [0, length),
+ * setter(arrayData, i, x) will be called where x is the value at the associated index.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ * \param setter the callback that will be called to set a value at a specific location in the
+ * array.
+ *
+ * \return STATUS_OK on successful read.
  */
-binder_status_t AParcel_readBoolArray(const AParcel* parcel, void** arrayData,
-                                      AParcel_arrayReallocator reallocator,
+binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_boolArrayAllocator allocator,
                                       AParcel_boolArraySetter setter) __INTRODUCED_IN(29);
 
 /**
  * Reads an array of char16_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
  */
-binder_status_t AParcel_readCharArray(const AParcel* parcel, void** arrayData,
-                                      AParcel_arrayReallocator reallocator,
-                                      AParcel_charArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_charArrayAllocator allocator) __INTRODUCED_IN(29);
 
 /**
  * Reads an array of int8_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
  */
-binder_status_t AParcel_readByteArray(const AParcel* parcel, void** arrayData,
-                                      AParcel_arrayReallocator reallocator,
-                                      AParcel_byteArrayGetter getter) __INTRODUCED_IN(29);
+binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_byteArrayAllocator allocator) __INTRODUCED_IN(29);
 
 // @END-PRIMITIVE-READ-WRITE
 
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
index faeb78f..2ccbe5a 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -28,32 +28,40 @@
 
 #include <android/binder_parcel.h>
 
-#ifdef __cplusplus
-
 #include <string>
 #include <vector>
 
 namespace ndk {
 
 /**
- * This resizes a std::vector of some underlying type to the given length.
+ * This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
  */
 template <typename T>
-static inline void* AParcel_stdVectorReallocator(void* vectorData, size_t length) {
+static inline T* AParcel_stdVectorAllocator(void* vectorData, size_t length) {
     std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
     if (length > vec->max_size()) return nullptr;
 
     vec->resize(length);
-    return vec;
+    return vec->data();
 }
 
 /**
- * This retrieves the underlying contiguous vector from a corresponding vectorData.
+ * This allocates a vector to size 'length' and returns whether the allocation is successful.
+ *
+ * See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined
+ * externally with respect to the NDK, and that size information is not passed into the NDK.
+ * Instead, it is used in cases where callbacks are used.
+ *
+ * See AParcel_readVector(const AParcel* parcel, std::vector<bool>)
+ * See AParcel_readVector(const AParcel* parcel, std::vector<std::string>)
  */
 template <typename T>
-static inline T* AParcel_stdVectorGetter(void* vectorData) {
+static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, size_t length) {
     std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
-    return vec->data();
+    if (length > vec->max_size()) return false;
+
+    vec->resize(length);
+    return true;
 }
 
 /**
@@ -76,212 +84,180 @@
     (*vec)[index] = value;
 }
 
-/**
- * Writes a vector to the next location in a non-null parcel.
- */
-template <typename T>
-static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<T>& vec);
-
-/**
- * Reads a vector to the next location in a non-null parcel.
- */
-template <typename T>
-static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<T>* vec);
-
 // @START
 /**
  * Writes a vector of int32_t to the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_writeVector<int32_t>(AParcel* parcel,
-                                                    const std::vector<int32_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) {
     return AParcel_writeInt32Array(parcel, vec.data(), vec.size());
 }
 
 /**
  * Reads a vector of int32_t from the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_readVector<int32_t>(const AParcel* parcel,
-                                                   std::vector<int32_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int32_t>* vec) {
     void* vectorData = static_cast<void*>(vec);
-    return AParcel_readInt32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int32_t>,
-                                  AParcel_stdVectorGetter<int32_t>);
+    return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>);
 }
 
 /**
  * Writes a vector of uint32_t to the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_writeVector<uint32_t>(AParcel* parcel,
-                                                     const std::vector<uint32_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) {
     return AParcel_writeUint32Array(parcel, vec.data(), vec.size());
 }
 
 /**
  * Reads a vector of uint32_t from the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_readVector<uint32_t>(const AParcel* parcel,
-                                                    std::vector<uint32_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint32_t>* vec) {
     void* vectorData = static_cast<void*>(vec);
-    return AParcel_readUint32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint32_t>,
-                                   AParcel_stdVectorGetter<uint32_t>);
+    return AParcel_readUint32Array(parcel, vectorData, AParcel_stdVectorAllocator<uint32_t>);
 }
 
 /**
  * Writes a vector of int64_t to the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_writeVector<int64_t>(AParcel* parcel,
-                                                    const std::vector<int64_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) {
     return AParcel_writeInt64Array(parcel, vec.data(), vec.size());
 }
 
 /**
  * Reads a vector of int64_t from the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_readVector<int64_t>(const AParcel* parcel,
-                                                   std::vector<int64_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int64_t>* vec) {
     void* vectorData = static_cast<void*>(vec);
-    return AParcel_readInt64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int64_t>,
-                                  AParcel_stdVectorGetter<int64_t>);
+    return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>);
 }
 
 /**
  * Writes a vector of uint64_t to the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_writeVector<uint64_t>(AParcel* parcel,
-                                                     const std::vector<uint64_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) {
     return AParcel_writeUint64Array(parcel, vec.data(), vec.size());
 }
 
 /**
  * Reads a vector of uint64_t from the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_readVector<uint64_t>(const AParcel* parcel,
-                                                    std::vector<uint64_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint64_t>* vec) {
     void* vectorData = static_cast<void*>(vec);
-    return AParcel_readUint64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint64_t>,
-                                   AParcel_stdVectorGetter<uint64_t>);
+    return AParcel_readUint64Array(parcel, vectorData, AParcel_stdVectorAllocator<uint64_t>);
 }
 
 /**
  * Writes a vector of float to the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_writeVector<float>(AParcel* parcel, const std::vector<float>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) {
     return AParcel_writeFloatArray(parcel, vec.data(), vec.size());
 }
 
 /**
  * Reads a vector of float from the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_readVector<float>(const AParcel* parcel, std::vector<float>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<float>* vec) {
     void* vectorData = static_cast<void*>(vec);
-    return AParcel_readFloatArray(parcel, &vectorData, &AParcel_stdVectorReallocator<float>,
-                                  AParcel_stdVectorGetter<float>);
+    return AParcel_readFloatArray(parcel, vectorData, AParcel_stdVectorAllocator<float>);
 }
 
 /**
  * Writes a vector of double to the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_writeVector<double>(AParcel* parcel,
-                                                   const std::vector<double>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) {
     return AParcel_writeDoubleArray(parcel, vec.data(), vec.size());
 }
 
 /**
  * Reads a vector of double from the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_readVector<double>(const AParcel* parcel, std::vector<double>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<double>* vec) {
     void* vectorData = static_cast<void*>(vec);
-    return AParcel_readDoubleArray(parcel, &vectorData, &AParcel_stdVectorReallocator<double>,
-                                   AParcel_stdVectorGetter<double>);
+    return AParcel_readDoubleArray(parcel, vectorData, AParcel_stdVectorAllocator<double>);
 }
 
 /**
  * Writes a vector of bool to the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_writeVector<bool>(AParcel* parcel, const std::vector<bool>& vec) {
-    return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec),
-                                  AParcel_stdVectorGetter<bool>, vec.size());
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) {
+    return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), vec.size(),
+                                  AParcel_stdVectorGetter<bool>);
 }
 
 /**
  * Reads a vector of bool from the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_readVector<bool>(const AParcel* parcel, std::vector<bool>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<bool>* vec) {
     void* vectorData = static_cast<void*>(vec);
-    return AParcel_readBoolArray(parcel, &vectorData, &AParcel_stdVectorReallocator<bool>,
+    return AParcel_readBoolArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<bool>,
                                  AParcel_stdVectorSetter<bool>);
 }
 
 /**
  * Writes a vector of char16_t to the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_writeVector<char16_t>(AParcel* parcel,
-                                                     const std::vector<char16_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) {
     return AParcel_writeCharArray(parcel, vec.data(), vec.size());
 }
 
 /**
  * Reads a vector of char16_t from the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_readVector<char16_t>(const AParcel* parcel,
-                                                    std::vector<char16_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<char16_t>* vec) {
     void* vectorData = static_cast<void*>(vec);
-    return AParcel_readCharArray(parcel, &vectorData, &AParcel_stdVectorReallocator<char16_t>,
-                                 AParcel_stdVectorGetter<char16_t>);
+    return AParcel_readCharArray(parcel, vectorData, AParcel_stdVectorAllocator<char16_t>);
 }
 
 /**
  * Writes a vector of int8_t to the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_writeVector<int8_t>(AParcel* parcel,
-                                                   const std::vector<int8_t>& vec) {
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int8_t>& vec) {
     return AParcel_writeByteArray(parcel, vec.data(), vec.size());
 }
 
 /**
  * Reads a vector of int8_t from the next location in a non-null parcel.
  */
-template <>
-inline binder_status_t AParcel_readVector<int8_t>(const AParcel* parcel, std::vector<int8_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int8_t>* vec) {
     void* vectorData = static_cast<void*>(vec);
-    return AParcel_readByteArray(parcel, &vectorData, &AParcel_stdVectorReallocator<int8_t>,
-                                 AParcel_stdVectorGetter<int8_t>);
+    return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>);
 }
 
 // @END
 
 /**
- * Takes a std::string and reallocates it to the specified length. For use with AParcel_readString.
- * See use below in AParcel_readString.
+ * Allocates a std::string to length and returns the underlying buffer. For use with
+ * AParcel_readString. See use below in AParcel_readString(const AParcel*, std::string*).
  */
-static inline void* AParcel_stdStringReallocator(void* stringData, size_t length) {
+static inline char* AParcel_stdStringAllocator(void* stringData, size_t length) {
     std::string* str = static_cast<std::string*>(stringData);
     str->resize(length - 1);
-    return stringData;
+    return &(*str)[0];
 }
 
 /**
- * Takes a std::string and returns the inner char*.
+ * Allocates a std::string inside of a std::vector<std::string> at index index to size 'length'.
  */
-static inline char* AParcel_stdStringGetter(void* stringData) {
-    std::string* str = static_cast<std::string*>(stringData);
-    return &(*str)[0];
+static inline char* AParcel_stdVectorStringElementAllocator(void* vectorData, size_t index,
+                                                            size_t length) {
+    std::vector<std::string>* vec = static_cast<std::vector<std::string>*>(vectorData);
+
+    std::string& element = vec->at(index);
+    element.resize(length - 1);
+    return &element[0];
+}
+
+/**
+ * This gets the length and buffer of a std::string inside of a std::vector<std::string> at index
+ * index.
+ */
+static inline const char* AParcel_stdVectorStringElementGetter(const void* vectorData, size_t index,
+                                                               size_t* outLength) {
+    const std::vector<std::string>* vec = static_cast<const std::vector<std::string>*>(vectorData);
+
+    const std::string& element = vec->at(index);
+
+    *outLength = element.size();
+    return element.c_str();
 }
 
 /**
@@ -296,10 +272,33 @@
  */
 static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) {
     void* stringData = static_cast<void*>(str);
-    return AParcel_readString(parcel, AParcel_stdStringReallocator, AParcel_stdStringGetter,
-                              &stringData);
+    return AParcel_readString(parcel, stringData, AParcel_stdStringAllocator);
 }
 
+/**
+ * Convenience API for writing a std::vector<std::string>
+ */
+static inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                                  const std::vector<std::string>& vec) {
+    const void* vectorData = static_cast<const void*>(&vec);
+    return AParcel_writeStringArray(parcel, vectorData, vec.size(),
+                                    AParcel_stdVectorStringElementGetter);
+}
+
+/**
+ * Convenience API for reading a std::vector<std::string>
+ */
+static inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                                 std::vector<std::string>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readStringArray(parcel, vectorData,
+                                   AParcel_stdVectorExternalAllocator<std::string>,
+                                   AParcel_stdVectorStringElementAllocator);
+}
+
+/**
+ * Convenience API for writing the size of a vector.
+ */
 template <typename T>
 static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, const std::vector<T>& vec) {
     if (vec.size() > INT32_MAX) {
@@ -309,6 +308,9 @@
     return AParcel_writeInt32(parcel, static_cast<int32_t>(vec.size()));
 }
 
+/**
+ * Convenience API for resizing a vector.
+ */
 template <typename T>
 static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, std::vector<T>* vec) {
     int32_t size;
@@ -321,8 +323,6 @@
     return STATUS_OK;
 }
 
-} // namespace ndk
-
-#endif // __cplusplus
+}  // namespace ndk
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index 2d8b7fa..2671b9b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -35,7 +35,7 @@
 enum {
     STATUS_OK = 0,
 
-    STATUS_UNKNOWN_ERROR = (-2147483647 - 1), // INT32_MIN value
+    STATUS_UNKNOWN_ERROR = (-2147483647 - 1),  // INT32_MIN value
     STATUS_NO_MEMORY = -ENOMEM,
     STATUS_INVALID_OPERATION = -ENOSYS,
     STATUS_BAD_VALUE = -EINVAL,
@@ -95,24 +95,39 @@
  * along with service specific errors.
  *
  * It is not required to be used in order to parcel/receive transactions, but it is required in
- * order to be compatible with standard AIDL transactions.
+ * order to be compatible with standard AIDL transactions since it is written as the header to the
+ * out parcel for transactions which get executed (don't fail during unparceling of input arguments
+ * or sooner).
  */
 struct AStatus;
 typedef struct AStatus AStatus;
 
 /**
  * New status which is considered a success.
+ *
+ * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29);
 
 /**
  * New status with exception code.
+ *
+ * \param exception the code that this status should represent. If this is EX_NONE, then this
+ * constructs an non-error status object.
+ *
+ * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCode(binder_exception_t exception)
         __INTRODUCED_IN(29);
 
 /**
  * New status with exception code and message.
+ *
+ * \param exception the code that this status should represent. If this is EX_NONE, then this
+ * constructs an non-error status object.
+ * \param message the error message to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCodeWithMessage(
         binder_exception_t exception, const char* message) __INTRODUCED_IN(29);
@@ -121,6 +136,10 @@
  * New status with a service speciic error.
  *
  * This is considered to be EX_TRANSACTION_FAILED with extra information.
+ *
+ * \param serviceSpecific an implementation defined error code.
+ *
+ * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificError(
         int32_t serviceSpecific) __INTRODUCED_IN(29);
@@ -129,6 +148,11 @@
  * New status with a service specific error and message.
  *
  * This is considered to be EX_TRANSACTION_FAILED with extra information.
+ *
+ * \param serviceSpecific an implementation defined error code.
+ * \param message the error message to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificErrorWithMessage(
         int32_t serviceSpecific, const char* message) __INTRODUCED_IN(29);
@@ -137,6 +161,10 @@
  * New status with binder_status_t. This is typically for low level failures when a binder_status_t
  * is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning
  * an AStatus instance.
+ *
+ * \param a low-level error to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromStatus(binder_status_t status)
         __INTRODUCED_IN(29);
@@ -144,11 +172,19 @@
 /**
  * Whether this object represents a successful transaction. If this function returns true, then
  * AStatus_getExceptionCode will return EX_NONE.
+ *
+ * \param status the status being queried.
+ *
+ * \return whether the status represents a successful transaction. For more details, see below.
  */
 bool AStatus_isOk(const AStatus* status) __INTRODUCED_IN(29);
 
 /**
  * The exception that this status object represents.
+ *
+ * \param status the status being queried.
+ *
+ * \return the exception code that this object represents.
  */
 binder_exception_t AStatus_getExceptionCode(const AStatus* status) __INTRODUCED_IN(29);
 
@@ -157,6 +193,10 @@
  * non-zero result if AStatus_getExceptionCode returns EX_SERVICE_SPECIFIC. If this function returns
  * 0, the status object may still represent a different exception or status. To find out if this
  * transaction as a whole is okay, use AStatus_isOk instead.
+ *
+ * \param status the status being queried.
+ *
+ * \return the service-specific error code if the exception code is EX_SERVICE_SPECIFIC or 0.
  */
 int32_t AStatus_getServiceSpecificError(const AStatus* status) __INTRODUCED_IN(29);
 
@@ -165,6 +205,10 @@
  * if AStatus_getExceptionCode returns EX_TRANSACTION_FAILED. If this function return 0, the status
  * object may represent a different exception or a service specific error. To find out if this
  * transaction as a whole is okay, use AStatus_isOk instead.
+ *
+ * \param status the status being queried.
+ *
+ * \return the status code if the exception code is EX_TRANSACTION_FAILED or 0.
  */
 binder_status_t AStatus_getStatus(const AStatus* status) __INTRODUCED_IN(29);
 
@@ -173,15 +217,21 @@
  * message, this will return an empty string.
  *
  * The returned string has the lifetime of the status object passed into this function.
+ *
+ * \param status the status being queried.
+ *
+ * \return the message associated with this error.
  */
 const char* AStatus_getMessage(const AStatus* status) __INTRODUCED_IN(29);
 
 /**
  * Deletes memory associated with the status instance.
+ *
+ * \param status the status to delete, returned from AStatus_newOk or one of the AStatus_from* APIs.
  */
 void AStatus_delete(AStatus* status) __INTRODUCED_IN(29);
 
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index f84814f..d2c1a3d 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -38,8 +38,10 @@
     AParcel_readInt64;
     AParcel_readInt64Array;
     AParcel_readNullableStrongBinder;
+    AParcel_readParcelFileDescriptor;
     AParcel_readStatusHeader;
     AParcel_readString;
+    AParcel_readStringArray;
     AParcel_readStrongBinder;
     AParcel_readUint32;
     AParcel_readUint32Array;
@@ -59,8 +61,10 @@
     AParcel_writeInt32Array;
     AParcel_writeInt64;
     AParcel_writeInt64Array;
+    AParcel_writeParcelFileDescriptor;
     AParcel_writeStatusHeader;
     AParcel_writeString;
+    AParcel_writeStringArray;
     AParcel_writeStrongBinder;
     AParcel_writeUint32;
     AParcel_writeUint32Array;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 29094db..8e5b477 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -23,16 +23,23 @@
 #include <limits>
 
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 #include <binder/Parcel.h>
+#include <binder/ParcelFileDescriptor.h>
 #include <utils/Unicode.h>
 
 using ::android::IBinder;
 using ::android::Parcel;
 using ::android::sp;
 using ::android::status_t;
+using ::android::base::unique_fd;
+using ::android::os::ParcelFileDescriptor;
 
 template <typename T>
-using ContiguousArrayGetter = T* (*)(void* arrayData);
+using ContiguousArrayAllocator = T* (*)(void* arrayData, size_t length);
+
+template <typename T>
+using ArrayAllocator = bool (*)(void* arrayData, size_t length);
 template <typename T>
 using ArrayGetter = T (*)(const void* arrayData, size_t index);
 template <typename T>
@@ -81,8 +88,8 @@
 }
 
 template <typename T>
-binder_status_t ReadArray(const AParcel* parcel, void** arrayData,
-                          AParcel_arrayReallocator reallocator, ContiguousArrayGetter<T> getter) {
+binder_status_t ReadArray(const AParcel* parcel, void* arrayData,
+                          ContiguousArrayAllocator<T> allocator) {
     const Parcel* rawParcel = parcel->get();
 
     int32_t length;
@@ -91,12 +98,8 @@
     if (status != STATUS_OK) return PruneStatusT(status);
     if (length < 0) return STATUS_UNEXPECTED_NULL;
 
-    *arrayData = reallocator(*arrayData, length);
-    if (*arrayData == nullptr) return STATUS_NO_MEMORY;
-
+    T* array = allocator(arrayData, length);
     if (length == 0) return STATUS_OK;
-
-    T* array = getter(*arrayData);
     if (array == nullptr) return STATUS_NO_MEMORY;
 
     int32_t size = 0;
@@ -112,9 +115,8 @@
 
 // Each element in a char16_t array is converted to an int32_t (not packed)
 template <>
-binder_status_t ReadArray<char16_t>(const AParcel* parcel, void** arrayData,
-                                    AParcel_arrayReallocator reallocator,
-                                    ContiguousArrayGetter<char16_t> getter) {
+binder_status_t ReadArray<char16_t>(const AParcel* parcel, void* arrayData,
+                                    ContiguousArrayAllocator<char16_t> allocator) {
     const Parcel* rawParcel = parcel->get();
 
     int32_t length;
@@ -123,12 +125,8 @@
     if (status != STATUS_OK) return PruneStatusT(status);
     if (length < 0) return STATUS_UNEXPECTED_NULL;
 
-    *arrayData = reallocator(*arrayData, length);
-    if (*arrayData == nullptr) return STATUS_NO_MEMORY;
-
+    char16_t* array = allocator(arrayData, length);
     if (length == 0) return STATUS_OK;
-
-    char16_t* array = getter(*arrayData);
     if (array == nullptr) return STATUS_NO_MEMORY;
 
     int32_t size = 0;
@@ -144,8 +142,8 @@
 }
 
 template <typename T>
-binder_status_t WriteArray(AParcel* parcel, const void* arrayData, ArrayGetter<T> getter,
-                           size_t length, status_t (Parcel::*write)(T)) {
+binder_status_t WriteArray(AParcel* parcel, const void* arrayData, size_t length,
+                           ArrayGetter<T> getter, status_t (Parcel::*write)(T)) {
     if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
 
     Parcel* rawParcel = parcel->get();
@@ -163,9 +161,8 @@
 }
 
 template <typename T>
-binder_status_t ReadArray(const AParcel* parcel, void** arrayData,
-                          AParcel_arrayReallocator reallocator, ArraySetter<T> setter,
-                          status_t (Parcel::*read)(T*) const) {
+binder_status_t ReadArray(const AParcel* parcel, void* arrayData, ArrayAllocator<T> allocator,
+                          ArraySetter<T> setter, status_t (Parcel::*read)(T*) const) {
     const Parcel* rawParcel = parcel->get();
 
     int32_t length;
@@ -174,15 +171,14 @@
     if (status != STATUS_OK) return PruneStatusT(status);
     if (length < 0) return STATUS_UNEXPECTED_NULL;
 
-    *arrayData = reallocator(*arrayData, length);
-    if (*arrayData == nullptr) return STATUS_NO_MEMORY;
+    if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
 
     for (size_t i = 0; i < length; i++) {
         T readTarget;
         status = (rawParcel->*read)(&readTarget);
         if (status != STATUS_OK) return PruneStatusT(status);
 
-        setter(*arrayData, i, readTarget);
+        setter(arrayData, i, readTarget);
     }
 
     return STATUS_OK;
@@ -218,16 +214,38 @@
     *binder = ret.get();
     return PruneStatusT(status);
 }
+
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) {
+    ParcelFileDescriptor parcelFd((unique_fd(fd)));
+
+    status_t status = parcel->get()->writeParcelable(parcelFd);
+
+    // ownership is retained by caller
+    (void)parcelFd.release().release();
+
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) {
+    ParcelFileDescriptor parcelFd;
+    // status_t status = parcelFd.readFromParcel(parcel->get());
+    status_t status = parcel->get()->readParcelable(&parcelFd);
+    if (status != STATUS_OK) return PruneStatusT(status);
+
+    *fd = parcelFd.release().release();
+    return STATUS_OK;
+}
+
 binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status) {
     return PruneStatusT(status->get()->writeToParcel(parcel->get()));
 }
 binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status) {
     ::android::binder::Status bstatus;
     binder_status_t ret = PruneStatusT(bstatus.readFromParcel(*parcel->get()));
-    if (ret == EX_NONE) {
+    if (ret == STATUS_OK) {
         *status = new AStatus(std::move(bstatus));
     }
-    return ret;
+    return PruneStatusT(ret);
 }
 
 binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) {
@@ -255,8 +273,8 @@
     return STATUS_OK;
 }
 
-binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringReallocator reallocator,
-                                   AParcel_stringGetter getter, void** stringData) {
+binder_status_t AParcel_readString(const AParcel* parcel, void* stringData,
+                                   AParcel_stringAllocator allocator) {
     size_t len16;
     const char16_t* str16 = parcel->get()->readString16Inplace(&len16);
 
@@ -273,21 +291,15 @@
         len8 = utf16_to_utf8_length(str16, len16) + 1;
     }
 
-    if (len8 <= 0 || len8 >= std::numeric_limits<int32_t>::max()) {
+    if (len8 <= 0 || len8 > std::numeric_limits<int32_t>::max()) {
         LOG(WARNING) << __func__ << ": Invalid string length: " << len8;
         return STATUS_BAD_VALUE;
     }
 
-    *stringData = reallocator(*stringData, len8);
-
-    if (*stringData == nullptr) {
-        return STATUS_NO_MEMORY;
-    }
-
-    char* str8 = getter(*stringData);
+    char* str8 = allocator(stringData, len8);
 
     if (str8 == nullptr) {
-        LOG(WARNING) << __func__ << ": AParcel_stringReallocator failed to allocate.";
+        LOG(WARNING) << __func__ << ": AParcel_stringAllocator failed to allocate.";
         return STATUS_NO_MEMORY;
     }
 
@@ -296,6 +308,68 @@
     return STATUS_OK;
 }
 
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, size_t length,
+                                         AParcel_stringArrayElementGetter getter) {
+    if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
+
+    Parcel* rawParcel = parcel->get();
+
+    status_t status = rawParcel->writeInt32(static_cast<int32_t>(length));
+    if (status != STATUS_OK) return PruneStatusT(status);
+
+    for (size_t i = 0; i < length; i++) {
+        size_t length = 0;
+        const char* str = getter(arrayData, i, &length);
+        if (str == nullptr) return STATUS_BAD_VALUE;
+
+        binder_status_t status = AParcel_writeString(parcel, str, length);
+        if (status != STATUS_OK) return status;
+    }
+
+    return STATUS_OK;
+}
+
+// This implements AParcel_stringAllocator for a string using an array, index, and element
+// allocator.
+struct StringArrayElementAllocationAdapter {
+    void* arrayData;  // stringData from the NDK
+    size_t index;     // index into the string array
+    AParcel_stringArrayElementAllocator elementAllocator;
+
+    static char* Allocator(void* stringData, size_t length) {
+        StringArrayElementAllocationAdapter* adapter =
+                static_cast<StringArrayElementAllocationAdapter*>(stringData);
+        return adapter->elementAllocator(adapter->arrayData, adapter->index, length);
+    }
+};
+
+binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData,
+                                        AParcel_stringArrayAllocator allocator,
+                                        AParcel_stringArrayElementAllocator elementAllocator) {
+    const Parcel* rawParcel = parcel->get();
+
+    int32_t length;
+    status_t status = rawParcel->readInt32(&length);
+
+    if (status != STATUS_OK) return PruneStatusT(status);
+    if (length < 0) return STATUS_UNEXPECTED_NULL;
+
+    if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+
+    StringArrayElementAllocationAdapter adapter{
+            .arrayData = arrayData,
+            .index = 0,
+            .elementAllocator = elementAllocator,
+    };
+
+    for (; adapter.index < length; adapter.index++) {
+        AParcel_readString(parcel, static_cast<void*>(&adapter),
+                           StringArrayElementAllocationAdapter::Allocator);
+    }
+
+    return STATUS_OK;
+}
+
 // See gen_parcel_helper.py. These auto-generated read/write methods use the same types for
 // libbinder and this library.
 // @START
@@ -389,95 +463,89 @@
     return PruneStatusT(status);
 }
 
-binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* value, size_t length) {
-    return WriteArray<int32_t>(parcel, value, length);
+binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, size_t length) {
+    return WriteArray<int32_t>(parcel, arrayData, length);
 }
 
-binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* value, size_t length) {
-    return WriteArray<uint32_t>(parcel, value, length);
+binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData,
+                                         size_t length) {
+    return WriteArray<uint32_t>(parcel, arrayData, length);
 }
 
-binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* value, size_t length) {
-    return WriteArray<int64_t>(parcel, value, length);
+binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, size_t length) {
+    return WriteArray<int64_t>(parcel, arrayData, length);
 }
 
-binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* value, size_t length) {
-    return WriteArray<uint64_t>(parcel, value, length);
+binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData,
+                                         size_t length) {
+    return WriteArray<uint64_t>(parcel, arrayData, length);
 }
 
-binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* value, size_t length) {
-    return WriteArray<float>(parcel, value, length);
+binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, size_t length) {
+    return WriteArray<float>(parcel, arrayData, length);
 }
 
-binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* value, size_t length) {
-    return WriteArray<double>(parcel, value, length);
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, size_t length) {
+    return WriteArray<double>(parcel, arrayData, length);
 }
 
-binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData,
-                                       AParcel_boolArrayGetter getter, size_t length) {
-    return WriteArray<bool>(parcel, arrayData, getter, length, &Parcel::writeBool);
+binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, size_t length,
+                                       AParcel_boolArrayGetter getter) {
+    return WriteArray<bool>(parcel, arrayData, length, getter, &Parcel::writeBool);
 }
 
-binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* value, size_t length) {
-    return WriteArray<char16_t>(parcel, value, length);
+binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, size_t length) {
+    return WriteArray<char16_t>(parcel, arrayData, length);
 }
 
-binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* value, size_t length) {
-    return WriteArray<int8_t>(parcel, value, length);
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, size_t length) {
+    return WriteArray<int8_t>(parcel, arrayData, length);
 }
 
-binder_status_t AParcel_readInt32Array(const AParcel* parcel, void** arrayData,
-                                       AParcel_arrayReallocator reallocator,
-                                       AParcel_int32ArrayGetter getter) {
-    return ReadArray<int32_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData,
+                                       AParcel_int32ArrayAllocator allocator) {
+    return ReadArray<int32_t>(parcel, arrayData, allocator);
 }
 
-binder_status_t AParcel_readUint32Array(const AParcel* parcel, void** arrayData,
-                                        AParcel_arrayReallocator reallocator,
-                                        AParcel_uint32ArrayGetter getter) {
-    return ReadArray<uint32_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData,
+                                        AParcel_uint32ArrayAllocator allocator) {
+    return ReadArray<uint32_t>(parcel, arrayData, allocator);
 }
 
-binder_status_t AParcel_readInt64Array(const AParcel* parcel, void** arrayData,
-                                       AParcel_arrayReallocator reallocator,
-                                       AParcel_int64ArrayGetter getter) {
-    return ReadArray<int64_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData,
+                                       AParcel_int64ArrayAllocator allocator) {
+    return ReadArray<int64_t>(parcel, arrayData, allocator);
 }
 
-binder_status_t AParcel_readUint64Array(const AParcel* parcel, void** arrayData,
-                                        AParcel_arrayReallocator reallocator,
-                                        AParcel_uint64ArrayGetter getter) {
-    return ReadArray<uint64_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData,
+                                        AParcel_uint64ArrayAllocator allocator) {
+    return ReadArray<uint64_t>(parcel, arrayData, allocator);
 }
 
-binder_status_t AParcel_readFloatArray(const AParcel* parcel, void** arrayData,
-                                       AParcel_arrayReallocator reallocator,
-                                       AParcel_floatArrayGetter getter) {
-    return ReadArray<float>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData,
+                                       AParcel_floatArrayAllocator allocator) {
+    return ReadArray<float>(parcel, arrayData, allocator);
 }
 
-binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void** arrayData,
-                                        AParcel_arrayReallocator reallocator,
-                                        AParcel_doubleArrayGetter getter) {
-    return ReadArray<double>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData,
+                                        AParcel_doubleArrayAllocator allocator) {
+    return ReadArray<double>(parcel, arrayData, allocator);
 }
 
-binder_status_t AParcel_readBoolArray(const AParcel* parcel, void** arrayData,
-                                      AParcel_arrayReallocator reallocator,
+binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_boolArrayAllocator allocator,
                                       AParcel_boolArraySetter setter) {
-    return ReadArray<bool>(parcel, arrayData, reallocator, setter, &Parcel::readBool);
+    return ReadArray<bool>(parcel, arrayData, allocator, setter, &Parcel::readBool);
 }
 
-binder_status_t AParcel_readCharArray(const AParcel* parcel, void** arrayData,
-                                      AParcel_arrayReallocator reallocator,
-                                      AParcel_charArrayGetter getter) {
-    return ReadArray<char16_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_charArrayAllocator allocator) {
+    return ReadArray<char16_t>(parcel, arrayData, allocator);
 }
 
-binder_status_t AParcel_readByteArray(const AParcel* parcel, void** arrayData,
-                                      AParcel_arrayReallocator reallocator,
-                                      AParcel_byteArrayGetter getter) {
-    return ReadArray<int8_t>(parcel, arrayData, reallocator, getter);
+binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_byteArrayAllocator allocator) {
+    return ReadArray<int8_t>(parcel, arrayData, allocator);
 }
 
 // @END
diff --git a/libs/binder/ndk/parcel_internal.h b/libs/binder/ndk/parcel_internal.h
index d69971f..f292309 100644
--- a/libs/binder/ndk/parcel_internal.h
+++ b/libs/binder/ndk/parcel_internal.h
@@ -29,7 +29,7 @@
 
     AParcel(const AIBinder* binder) : AParcel(binder, new ::android::Parcel, true /*owns*/) {}
     AParcel(const AIBinder* binder, ::android::Parcel* parcel, bool owns)
-          : mBinder(binder), mParcel(parcel), mOwns(owns) {}
+        : mBinder(binder), mParcel(parcel), mOwns(owns) {}
 
     ~AParcel() {
         if (mOwns) {
@@ -43,7 +43,7 @@
 
     const AIBinder* getBinder() { return mBinder; }
 
-private:
+   private:
     // This object is associated with a calls to a specific AIBinder object. This is used for sanity
     // checking to make sure that a parcel is one that is expected.
     const AIBinder* mBinder;
diff --git a/libs/binder/ndk/runtests.sh b/libs/binder/ndk/runtests.sh
index 2257eb2..a0c49fb 100755
--- a/libs/binder/ndk/runtests.sh
+++ b/libs/binder/ndk/runtests.sh
@@ -22,12 +22,13 @@
 set -ex
 
 function run_libbinder_ndk_test() {
-	adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
-	local pid=$!
-	trap "kill $pid" ERR
-	adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client
-	trap '' ERR
-	kill $pid
+    adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
+
+    # avoid getService 1s delay for most runs, non-critical
+    sleep 0.1
+
+    adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client; \
+        adb shell killall libbinder_ndk_test_server
 }
 
 [ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \
@@ -40,4 +41,5 @@
 # very simple unit tests, tests things outside of the NDK as well
 run_libbinder_ndk_test
 
-atest android.binder.cts.NdkBinderTest
+# CTS tests (much more comprehensive, new tests should ideally go here)
+atest android.binder.cts
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
index 45f8d06..bb76254 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -69,6 +69,11 @@
     for pretty, cpp in data_types:
         header += "/**\n"
         header += " * Writes " + cpp + " value to the next location in a non-null parcel.\n"
+        header += " *\n"
+        header += " * \\param parcel the parcel to write to.\n"
+        header += " * \\param value the value to write to the parcel.\n"
+        header += " *\n"
+        header += " * \\return STATUS_OK on successful write.\n"
         header += " */\n"
         header += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) __INTRODUCED_IN(29);\n\n"
         source += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) {\n"
@@ -79,6 +84,11 @@
     for pretty, cpp in data_types:
         header += "/**\n"
         header += " * Reads into " + cpp + " value from the next location in a non-null parcel.\n"
+        header += " *\n"
+        header += " * \\param parcel the parcel to read from.\n"
+        header += " * \\param value the value to read from the parcel.\n"
+        header += " *\n"
+        header += " * \\return STATUS_OK on successful read.\n"
         header += " */\n"
         header += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) __INTRODUCED_IN(29);\n\n"
         source += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) {\n"
@@ -89,87 +99,151 @@
     for pretty, cpp in data_types:
         nca = pretty in non_contiguously_addressable
 
-        arg_type = "const " + cpp + "* value"
-        if nca: arg_type = "const void* arrayData, AParcel_" + pretty.lower() + "ArrayGetter getter"
-        args = "value, length"
-        if nca: args = "arrayData, getter, length, &Parcel::write" + pretty
+        arg_types = "const " + cpp + "* arrayData, size_t length"
+        if nca: arg_types = "const void* arrayData, size_t length, AParcel_" + pretty.lower() + "ArrayGetter getter"
+        args = "arrayData, length"
+        if nca: args = "arrayData, length, getter, &Parcel::write" + pretty
 
         header += "/**\n"
         header += " * Writes an array of " + cpp + " to the next location in a non-null parcel.\n"
+        if nca:
+            header += " *\n"
+            header += " * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying values to write "
+            header += "to the parcel.\n"
+        header += " *\n"
+        header += " * \\param parcel the parcel to write to.\n"
+        if nca:
+            header += " * \\param arrayData some external representation of an array.\n"
+            header += " * \\param length the length of arrayData.\n"
+            header += " * \\param getter the callback to retrieve data at specific locations in the array.\n"
+        else:
+            header += " * \\param arrayData an array of size 'length'.\n"
+            header += " * \\param length the length of arrayData.\n"
+        header += " *\n"
+        header += " * \\return STATUS_OK on successful write.\n"
         header += " */\n"
-        header += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_type + ", size_t length) __INTRODUCED_IN(29);\n\n"
-        source += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_type + ", size_t length) {\n"
+        header += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_types + ") __INTRODUCED_IN(29);\n\n"
+        source += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_types + ") {\n"
         source += "    return WriteArray<" + cpp + ">(parcel, " + args + ");\n";
         source += "}\n\n"
 
     for pretty, cpp in data_types:
         nca = pretty in non_contiguously_addressable
 
-        extra_getter_args = ""
-        if nca: extra_getter_args = ", size_t index"
-        getter_return = cpp + "*"
-        if nca: getter_return = cpp
-        getter_array_data = "void* arrayData"
-        if nca: getter_array_data = "const void* arrayData"
-
+        read_func = "AParcel_read" + pretty + "Array"
+        write_func = "AParcel_write" + pretty + "Array"
+        allocator_type = "AParcel_" + pretty.lower() + "ArrayAllocator"
         getter_type = "AParcel_" + pretty.lower() + "ArrayGetter"
         setter_type = "AParcel_" + pretty.lower() + "ArraySetter"
 
-        pre_header += "/**\n"
-        pre_header += " * This is called to get the underlying data from an arrayData object.\n"
-        pre_header += " *\n"
-        pre_header += " * This will never be called for an empty array.\n"
-        pre_header += " */\n"
-        pre_header += "typedef " + getter_return + " (*" + getter_type + ")(" + getter_array_data + extra_getter_args + ");\n\n"
-
         if nca:
             pre_header += "/**\n"
+            pre_header += " * This allocates an array of size 'length' inside of arrayData and returns whether or not there was "
+            pre_header += "a success.\n"
+            pre_header += " *\n"
+            pre_header += " * See also " + read_func + "\n"
+            pre_header += " *\n"
+            pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+            pre_header += " * \\param length the length to allocate arrayData to.\n"
+            pre_header += " *\n"
+            pre_header += " * \\return whether the allocation succeeded.\n"
+            pre_header += " */\n"
+            pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, size_t length);\n\n"
+
+            pre_header += "/**\n"
+            pre_header += " * This is called to get the underlying data from an arrayData object at index.\n"
+            pre_header += " *\n"
+            pre_header += " * See also " + write_func + "\n"
+            pre_header += " *\n"
+            pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+            pre_header += " * \\param index the index of the value to be retrieved.\n"
+            pre_header += " *\n"
+            pre_header += " * \\return the value of the array at index index.\n"
+            pre_header += " */\n"
+            pre_header += "typedef " + cpp + " (*" + getter_type + ")(const void* arrayData, size_t index);\n\n"
+
+            pre_header += "/**\n"
             pre_header += " * This is called to set an underlying value in an arrayData object at index.\n"
+            pre_header += " *\n"
+            pre_header += " * See also " + read_func + "\n"
+            pre_header += " *\n"
+            pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+            pre_header += " * \\param index the index of the value to be set.\n"
+            pre_header += " * \\param value the value to set at index index.\n"
             pre_header += " */\n"
             pre_header += "typedef void (*" + setter_type + ")(void* arrayData, size_t index, " + cpp + " value);\n\n"
+        else:
+            pre_header += "/**\n"
+            pre_header += " * This is called to get the underlying data from an arrayData object.\n"
+            pre_header += " *\n"
+            pre_header += " * The implementation of this function should allocate a contiguous array of size 'length' and "
+            pre_header += "return that underlying buffer to be filled out. If there is an error or length is 0, null may be "
+            pre_header += "returned.\n"
+            pre_header += " *\n"
+            pre_header += " * See also " + read_func + "\n"
+            pre_header += " *\n"
+            pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+            pre_header += " * \\param length the length to allocate arrayData to.\n"
+            pre_header += " *\n"
+            pre_header += " * \\return a buffer of " + cpp + " of size 'length'.\n"
+            pre_header += " */\n"
+            pre_header += "typedef " + cpp + "* (*" + allocator_type + ")(void* arrayData, size_t length);\n\n"
 
-        read_using = "getter"
-        if nca: read_using = "setter"
-        read_type = getter_type
-        if nca: read_type = setter_type
+        read_array_args = [("const AParcel*", "parcel")]
+        read_array_args += [("void*", "arrayData")]
+        read_array_args += [(allocator_type, "allocator")]
+        if nca: read_array_args += [(setter_type, "setter")]
 
-        arguments = ["const AParcel* parcel"]
-        arguments += ["void** arrayData"]
-        arguments += ["AParcel_arrayReallocator reallocator"]
-        arguments += [read_type + " " + read_using]
-        arguments = ", ".join(arguments)
+        read_type_args = ", ".join((varType + " " + name for varType, name in read_array_args))
+        read_call_args = ", ".join((name for varType, name in read_array_args))
 
         header += "/**\n"
         header += " * Reads an array of " + cpp + " from the next location in a non-null parcel.\n"
+        header += " *\n"
+        if nca:
+            header += " * First, allocator will be called with the length of the array. Then, for every i in [0, length), "
+            header += "setter(arrayData, i, x) will be called where x is the value at the associated index.\n"
+        else:
+            header += " * First, allocator will be called with the length of the array. If the allocation succeeds and the "
+            header += "length is greater than zero, the buffer returned by the allocator will be filled with the corresponding data\n"
+        header += " *\n"
+        header += " * \\param parcel the parcel to read from.\n"
+        header += " * \\param arrayData some external representation of an array.\n"
+        header += " * \\param allocator the callback that will be called to allocate the array.\n"
+        if nca:
+            header += " * \\param setter the callback that will be called to set a value at a specific location in the array.\n"
+        header += " *\n"
+        header += " * \\return STATUS_OK on successful read.\n"
         header += " */\n"
-        header += "binder_status_t AParcel_read" + pretty + "Array(" + arguments + ") __INTRODUCED_IN(29);\n\n"
-        source += "binder_status_t AParcel_read" + pretty + "Array(" + arguments + ") {\n"
+        header += "binder_status_t " + read_func + "(" + read_type_args + ") __INTRODUCED_IN(29);\n\n"
+        source += "binder_status_t " + read_func + "(" + read_type_args + ") {\n"
         additional_args = ""
         if nca: additional_args = ", &Parcel::read" + pretty
-        source += "    return ReadArray<" + cpp + ">(parcel, arrayData, reallocator, " + read_using + additional_args + ");\n";
+        source += "    return ReadArray<" + cpp + ">(" + read_call_args + additional_args + ");\n";
         source += "}\n\n"
 
         cpp_helper += "/**\n"
         cpp_helper += " * Writes a vector of " + cpp + " to the next location in a non-null parcel.\n"
         cpp_helper += " */\n"
-        cpp_helper += "template<>\n"
-        cpp_helper += "inline binder_status_t AParcel_writeVector<" + cpp + ">(AParcel* parcel, const std::vector<" + cpp + ">& vec) {\n"
-        write_args = "vec.data()"
-        if nca: write_args = "static_cast<const void*>(&vec), AParcel_stdVectorGetter<" + cpp + ">"
-        cpp_helper += "    return AParcel_write" + pretty + "Array(parcel, " + write_args + ", vec.size());\n"
+        cpp_helper += "inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<" + cpp + ">& vec) {\n"
+        write_args = "vec.data(), vec.size()"
+        if nca: write_args = "static_cast<const void*>(&vec), vec.size(), AParcel_stdVectorGetter<" + cpp + ">"
+        cpp_helper += "    return AParcel_write" + pretty + "Array(parcel, " + write_args + ");\n"
         cpp_helper += "}\n\n"
 
         cpp_helper += "/**\n"
         cpp_helper += " * Reads a vector of " + cpp + " from the next location in a non-null parcel.\n"
         cpp_helper += " */\n"
-        cpp_helper += "template<>\n"
-        cpp_helper += "inline binder_status_t AParcel_readVector<" + cpp + ">(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n"
+        cpp_helper += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n"
         cpp_helper += "    void* vectorData = static_cast<void*>(vec);\n"
         read_args = []
         read_args += ["parcel"]
-        read_args += ["&vectorData"]
-        read_args += ["&AParcel_stdVectorReallocator<" + cpp + ">"]
-        read_args += ["AParcel_stdVector" + read_using.capitalize() + "<" + cpp + ">"]
+        read_args += ["vectorData"]
+        if nca:
+            read_args += ["AParcel_stdVectorExternalAllocator<bool>"]
+            read_args += ["AParcel_stdVectorSetter<" + cpp + ">"]
+        else:
+            read_args += ["AParcel_stdVectorAllocator<" + cpp + ">"]
         cpp_helper += "    return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n"
         cpp_helper += "}\n\n"
 
diff --git a/libs/binder/ndk/status_internal.h b/libs/binder/ndk/status_internal.h
index 8c32baf..d39f0d8 100644
--- a/libs/binder/ndk/status_internal.h
+++ b/libs/binder/ndk/status_internal.h
@@ -22,13 +22,13 @@
 #include <utils/Errors.h>
 
 struct AStatus {
-    AStatus() {} // ok
+    AStatus() {}  // ok
     AStatus(::android::binder::Status&& status) : mStatus(std::move(status)) {}
 
     ::android::binder::Status* get() { return &mStatus; }
     const ::android::binder::Status* get() const { return &mStatus; }
 
-private:
+   private:
     ::android::binder::Status mStatus;
 };
 
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 8e40a01..b29b6e7 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-// This test is a unit test of the low-level API that is presented here.
-// Actual users should use AIDL to generate these complicated stubs.
-
 cc_defaults {
     name: "test_libbinder_ndk_defaults",
     shared_libs: [
@@ -55,6 +52,9 @@
     ],
 }
 
+// This test is a unit test of the low-level API that is presented here,
+// specifically the parts which are outside of the NDK. Actual users should
+// also instead use AIDL to generate these stubs. See android.binder.cts.
 cc_test {
     name: "libbinder_ndk_test_client",
     defaults: ["test_libbinder_ndk_test_defaults"],
diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/test/iface.cpp
index 0dc3cc4..6ef964e 100644
--- a/libs/binder/ndk/test/iface.cpp
+++ b/libs/binder/ndk/test/iface.cpp
@@ -18,10 +18,13 @@
 #include <android/binder_manager.h>
 #include <iface/iface.h>
 
+#include <android/binder_auto_utils.h>
+
 using ::android::sp;
 using ::android::wp;
 
 const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo";
+const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die";
 const char* kIFooDescriptor = "my-special-IFoo-class";
 
 struct IFoo_Class_Data {
@@ -49,12 +52,18 @@
     switch (code) {
         case IFoo::DOFOO: {
             int32_t valueIn;
+            int32_t valueOut;
             stat = AParcel_readInt32(in, &valueIn);
             if (stat != STATUS_OK) break;
-            int32_t valueOut = foo->doubleNumber(valueIn);
+            stat = foo->doubleNumber(valueIn, &valueOut);
+            if (stat != STATUS_OK) break;
             stat = AParcel_writeInt32(out, valueOut);
             break;
         }
+        case IFoo::DIE: {
+            stat = foo->die();
+            break;
+        }
     }
 
     return stat;
@@ -64,29 +73,43 @@
                                                      IFoo_Class_onDestroy, IFoo_Class_onTransact);
 
 class BpFoo : public IFoo {
-public:
+   public:
     BpFoo(AIBinder* binder) : mBinder(binder) {}
     virtual ~BpFoo() { AIBinder_decStrong(mBinder); }
 
-    virtual int32_t doubleNumber(int32_t in) {
+    virtual binder_status_t doubleNumber(int32_t in, int32_t* out) {
+        binder_status_t stat = STATUS_OK;
+
         AParcel* parcelIn;
-        CHECK(STATUS_OK == AIBinder_prepareTransaction(mBinder, &parcelIn));
+        stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
+        if (stat != STATUS_OK) return stat;
 
-        CHECK(STATUS_OK == AParcel_writeInt32(parcelIn, in));
+        stat = AParcel_writeInt32(parcelIn, in);
+        if (stat != STATUS_OK) return stat;
 
-        AParcel* parcelOut;
-        CHECK(STATUS_OK ==
-              AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, &parcelOut, 0 /*flags*/));
+        ::ndk::ScopedAParcel parcelOut;
+        stat = AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, parcelOut.getR(), 0 /*flags*/);
+        if (stat != STATUS_OK) return stat;
 
-        int32_t out;
-        CHECK(STATUS_OK == AParcel_readInt32(parcelOut, &out));
+        stat = AParcel_readInt32(parcelOut.get(), out);
+        if (stat != STATUS_OK) return stat;
 
-        AParcel_delete(parcelOut);
-
-        return out;
+        return stat;
     }
 
-private:
+    virtual binder_status_t die() {
+        binder_status_t stat = STATUS_OK;
+
+        AParcel* parcelIn;
+        stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
+
+        ::ndk::ScopedAParcel parcelOut;
+        stat = AIBinder_transact(mBinder, IFoo::DIE, &parcelIn, parcelOut.getR(), 0 /*flags*/);
+
+        return stat;
+    }
+
+   private:
     // Always assumes one refcount
     AIBinder* mBinder;
 };
@@ -117,8 +140,8 @@
     return status;
 }
 
-sp<IFoo> IFoo::getService(const char* instance) {
-    AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr
+sp<IFoo> IFoo::getService(const char* instance, AIBinder** outBinder) {
+    AIBinder* binder = AServiceManager_getService(instance);  // maybe nullptr
     if (binder == nullptr) {
         return nullptr;
     }
@@ -128,14 +151,19 @@
         return nullptr;
     }
 
+    if (outBinder != nullptr) {
+        AIBinder_incStrong(binder);
+        *outBinder = binder;
+    }
+
     if (AIBinder_isRemote(binder)) {
-        sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder
+        sp<IFoo> ret = new BpFoo(binder);  // takes ownership of binder
         return ret;
     }
 
     IFoo_Class_Data* data = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder));
 
-    CHECK(data != nullptr); // always created with non-null data
+    CHECK(data != nullptr);  // always created with non-null data
 
     sp<IFoo> ret = data->foo;
 
@@ -143,7 +171,6 @@
     CHECK(held == binder);
     AIBinder_decStrong(held);
 
-    // IFoo only keeps a weak reference to AIBinder, so we can drop this
     AIBinder_decStrong(binder);
     return ret;
 }
diff --git a/libs/binder/ndk/test/include/iface/iface.h b/libs/binder/ndk/test/include/iface/iface.h
index 4c61e9d..cdf5493 100644
--- a/libs/binder/ndk/test/include/iface/iface.h
+++ b/libs/binder/ndk/test/include/iface/iface.h
@@ -19,22 +19,33 @@
 #include <android/binder_ibinder.h>
 #include <utils/RefBase.h>
 
+// warning: it is recommended to use AIDL output instead of this. binder_ibinder_utils.h and some of
+// the other niceties make sure that, for instance, binder proxies are always the same. They also
+// don't use internal Android APIs like refbase which are used here only for convenience.
+
 class IFoo : public virtual ::android::RefBase {
-public:
+   public:
     static const char* kSomeInstanceName;
+    static const char* kInstanceNameToDieFor;
+
     static AIBinder_Class* kClass;
 
     // Takes ownership of IFoo
     binder_status_t addService(const char* instance);
-    static ::android::sp<IFoo> getService(const char* instance);
+    static ::android::sp<IFoo> getService(const char* instance, AIBinder** outBinder = nullptr);
 
     enum Call {
         DOFOO = FIRST_CALL_TRANSACTION + 0,
+        DIE = FIRST_CALL_TRANSACTION + 1,
     };
 
     virtual ~IFoo();
-    virtual int32_t doubleNumber(int32_t in) = 0;
 
-private:
-    AIBinder_Weak* mWeakBinder = nullptr; // maybe owns AIBinder
+    virtual binder_status_t doubleNumber(int32_t in, int32_t* out) = 0;
+    virtual binder_status_t die() = 0;
+
+   private:
+    // this variable is only when IFoo is local (since this test combines 'IFoo' and 'BnFoo'), not
+    // for BpFoo.
+    AIBinder_Weak* mWeakBinder = nullptr;
 };
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index 6945cac..c159d71 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -21,6 +21,10 @@
 #include <gtest/gtest.h>
 #include <iface/iface.h>
 
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
 using ::android::sp;
 
 constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
@@ -34,7 +38,47 @@
 TEST(NdkBinder, DoubleNumber) {
     sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
     ASSERT_NE(foo, nullptr);
-    EXPECT_EQ(2, foo->doubleNumber(1));
+
+    int32_t out;
+    EXPECT_EQ(STATUS_OK, foo->doubleNumber(1, &out));
+    EXPECT_EQ(2, out);
+}
+
+void LambdaOnDeath(void* cookie) {
+    auto onDeath = static_cast<std::function<void(void)>*>(cookie);
+    (*onDeath)();
+};
+TEST(NdkBinder, DeathRecipient) {
+    using namespace std::chrono_literals;
+
+    AIBinder* binder;
+    sp<IFoo> foo = IFoo::getService(IFoo::kInstanceNameToDieFor, &binder);
+    ASSERT_NE(nullptr, foo.get());
+    ASSERT_NE(nullptr, binder);
+
+    std::mutex deathMutex;
+    std::condition_variable deathCv;
+    bool deathRecieved = false;
+
+    std::function<void(void)> onDeath = [&] {
+        std::cerr << "Binder died (as requested)." << std::endl;
+        deathRecieved = true;
+        deathCv.notify_one();
+    };
+
+    AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath);
+
+    EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath)));
+
+    // the binder driver should return this if the service dies during the transaction
+    EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
+
+    std::unique_lock<std::mutex> lock(deathMutex);
+    EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; }));
+    EXPECT_TRUE(deathRecieved);
+
+    AIBinder_DeathRecipient_delete(recipient);
+    AIBinder_decStrong(binder);
 }
 
 TEST(NdkBinder, RetrieveNonNdkService) {
@@ -52,9 +96,6 @@
 }
 
 TEST(NdkBinder, LinkToDeath) {
-    ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications
-    ABinderProcess_startThreadPool();
-
     AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
     ASSERT_NE(nullptr, binder);
 
@@ -72,9 +113,14 @@
 }
 
 class MyTestFoo : public IFoo {
-    int32_t doubleNumber(int32_t in) override {
-        LOG(INFO) << "doubleNumber " << in;
-        return 2 * in;
+    binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+        *out = 2 * in;
+        LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+        return STATUS_OK;
+    }
+    binder_status_t die() override {
+        ADD_FAILURE() << "die called on local instance";
+        return STATUS_OK;
     }
 };
 
@@ -87,7 +133,9 @@
     sp<IFoo> getFoo = IFoo::getService(kInstanceName);
     EXPECT_EQ(foo.get(), getFoo.get());
 
-    EXPECT_EQ(2, getFoo->doubleNumber(1));
+    int32_t out;
+    EXPECT_EQ(STATUS_OK, getFoo->doubleNumber(1, &out));
+    EXPECT_EQ(2, out);
 }
 
 TEST(NdkBinder, EqualityOfRemoteBinderPointer) {
@@ -132,6 +180,15 @@
     EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
 }
 
+int main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    ABinderProcess_setThreadPoolMaxThreadCount(1);  // to recieve death notifications/callbacks
+    ABinderProcess_startThreadPool();
+
+    return RUN_ALL_TESTS();
+}
+
 #include <android/binder_auto_utils.h>
 #include <android/binder_interface_utils.h>
 #include <android/binder_parcel_utils.h>
diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp
index 0718a69..a6e17e8 100644
--- a/libs/binder/ndk/test/main_server.cpp
+++ b/libs/binder/ndk/test/main_server.cpp
@@ -21,23 +21,37 @@
 using ::android::sp;
 
 class MyFoo : public IFoo {
-    int32_t doubleNumber(int32_t in) override {
-        LOG(INFO) << "doubling " << in;
-        return 2 * in;
+    binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+        *out = 2 * in;
+        LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+        return STATUS_OK;
+    }
+
+    binder_status_t die() override {
+        LOG(FATAL) << "IFoo::die called!";
+        return STATUS_UNKNOWN_ERROR;
     }
 };
 
-int main() {
+int service(const char* instance) {
     ABinderProcess_setThreadPoolMaxThreadCount(0);
 
     // Strong reference to MyFoo kept by service manager.
-    binder_status_t status = (new MyFoo)->addService(IFoo::kSomeInstanceName);
+    binder_status_t status = (new MyFoo)->addService(instance);
 
     if (status != STATUS_OK) {
-        LOG(FATAL) << "Could not register: " << status;
+        LOG(FATAL) << "Could not register: " << status << " " << instance;
     }
 
     ABinderProcess_joinThreadPool();
 
-    return 1;
+    return 1;  // should not return
+}
+
+int main() {
+    if (fork() == 0) {
+        return service(IFoo::kInstanceNameToDieFor);
+    }
+
+    return service(IFoo::kSomeInstanceName);
 }
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 024d72b..afa32b6 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -68,8 +68,7 @@
 }
 
 void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
-                               const std::string appPref, bool developerOptIn,
-                               const int rulesFd, const long rulesOffset,
+                               bool developerOptIn, const int rulesFd, const long rulesOffset,
                                const long rulesLength) {
     if (!mAnglePath.empty()) {
         ALOGV("ignoring attempt to change ANGLE path from '%s' to '%s'", mAnglePath.c_str(),
@@ -87,14 +86,6 @@
         mAngleAppName = appName;
     }
 
-    if (!mAngleAppPref.empty()) {
-        ALOGV("ignoring attempt to change ANGLE application opt-in from '%s' to '%s'",
-              mAngleAppPref.c_str(), appPref.c_str());
-    } else {
-        ALOGV("setting ANGLE application opt-in to '%s'", appPref.c_str());
-        mAngleAppPref = appPref;
-    }
-
     mAngleDeveloperOptIn = developerOptIn;
 
     ALOGV("setting ANGLE rules file descriptor to '%i'", rulesFd);
@@ -128,11 +119,6 @@
     return mAngleDeveloperOptIn;
 }
 
-const char* GraphicsEnv::getAngleAppPref() {
-    if (mAngleAppPref.empty()) return nullptr;
-    return mAngleAppPref.c_str();
-}
-
 int GraphicsEnv::getAngleRulesFd() {
     return mAngleRulesFd;
 }
@@ -145,18 +131,26 @@
     return mAngleRulesLength;
 }
 
-const std::string GraphicsEnv::getLayerPaths(){
+const std::string& GraphicsEnv::getLayerPaths() {
     return mLayerPaths;
 }
 
-const std::string GraphicsEnv::getDebugLayers() {
+const std::string& GraphicsEnv::getDebugLayers() {
     return mDebugLayers;
 }
 
+const std::string& GraphicsEnv::getDebugLayersGLES() {
+    return mDebugLayersGLES;
+}
+
 void GraphicsEnv::setDebugLayers(const std::string layers) {
     mDebugLayers = layers;
 }
 
+void GraphicsEnv::setDebugLayersGLES(const std::string layers) {
+    mDebugLayersGLES = layers;
+}
+
 android_namespace_t* GraphicsEnv::getDriverNamespace() {
     static std::once_flag once;
     std::call_once(once, [this]() {
@@ -196,36 +190,3 @@
 }
 
 } // namespace android
-
-extern "C" {
-android_namespace_t* android_getDriverNamespace() {
-    return android::GraphicsEnv::getInstance().getDriverNamespace();
-}
-android_namespace_t* android_getAngleNamespace() {
-    return android::GraphicsEnv::getInstance().getAngleNamespace();
-}
-const char* android_getAngleAppName() {
-    return android::GraphicsEnv::getInstance().getAngleAppName();
-}
-bool android_getAngleDeveloperOptIn() {
-    return android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
-}
-const char* android_getAngleAppPref() {
-    return android::GraphicsEnv::getInstance().getAngleAppPref();
-}
-int android_getAngleRulesFd() {
-   return android::GraphicsEnv::getInstance().getAngleRulesFd();
-}
-long android_getAngleRulesOffset() {
-   return android::GraphicsEnv::getInstance().getAngleRulesOffset();
-}
-long android_getAngleRulesLength() {
-   return android::GraphicsEnv::getInstance().getAngleRulesLength();
-}
-const char* android_getLayerPaths() {
-    return android::GraphicsEnv::getInstance().getLayerPaths().c_str();
-}
-const char* android_getDebugLayers() {
-    return android::GraphicsEnv::getInstance().getDebugLayers().c_str();
-}
-}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 404823a..20e4d66 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -44,9 +44,8 @@
     // (libraries must be stored uncompressed and page aligned); such elements
     // in the search path must have a '!' after the zip filename, e.g.
     //     /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
-    void setAngleInfo(const std::string path, const std::string appName, const std::string appPref,
-                      bool devOptIn, const int rulesFd, const long rulesOffset,
-                      const long rulesLength);
+    void setAngleInfo(const std::string path, const std::string appName, bool devOptIn,
+                      const int rulesFd, const long rulesOffset, const long rulesLength);
     android_namespace_t* getAngleNamespace();
     const char* getAngleAppName();
     const char* getAngleAppPref();
@@ -58,22 +57,24 @@
     void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths);
     NativeLoaderNamespace* getAppNamespace();
 
-    const std::string getLayerPaths();
+    const std::string& getLayerPaths();
 
     void setDebugLayers(const std::string layers);
-    const std::string getDebugLayers();
+    void setDebugLayersGLES(const std::string layers);
+    const std::string& getDebugLayers();
+    const std::string& getDebugLayersGLES();
 
 private:
     GraphicsEnv() = default;
     std::string mDriverPath;
     std::string mAnglePath;
     std::string mAngleAppName;
-    std::string mAngleAppPref;
     bool mAngleDeveloperOptIn;
     int mAngleRulesFd;
     long mAngleRulesOffset;
     long mAngleRulesLength;
     std::string mDebugLayers;
+    std::string mDebugLayersGLES;
     std::string mLayerPaths;
     android_namespace_t* mDriverNamespace = nullptr;
     android_namespace_t* mAngleNamespace = nullptr;
@@ -82,28 +83,4 @@
 
 } // namespace android
 
-/* FIXME
- * Export an un-mangled function that just does
- *     return android::GraphicsEnv::getInstance().getDriverNamespace();
- * This allows libEGL to get the function pointer via dlsym, since it can't
- * directly link against libgui. In a future release, we'll fix this so that
- * libgui does not depend on graphics API libraries, and libEGL can link
- * against it. The current dependencies from libgui -> libEGL are:
- *  - the GLConsumer class, which should be moved to its own library
- *  - the EGLsyncKHR synchronization in BufferQueue, which is deprecated and
- *    will be removed soon.
- */
-extern "C" {
-    android_namespace_t* android_getDriverNamespace();
-    android_namespace_t* android_getAngleNamespace();
-    const char* android_getAngleAppName();
-    const char* android_getAngleAppPref();
-    bool android_getAngleDeveloperOptIn();
-    int android_getAngleRulesFd();
-    long android_getAngleRulesOffset();
-    long android_getAngleRulesLength();
-    const char* android_getLayerPaths();
-    const char* android_getDebugLayers();
-}
-
 #endif // ANDROID_UI_GRAPHICS_ENV_H
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 98264ac..7677c3a 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -107,6 +107,7 @@
         "IProducerListener.cpp",
         "ISurfaceComposer.cpp",
         "ISurfaceComposerClient.cpp",
+        "ITransactionCompletedListener.cpp",
         "LayerDebugInfo.cpp",
         "LayerState.cpp",
         "OccupancyTracker.cpp",
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index 1a7c2d3..ed773e0 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -20,7 +20,6 @@
 #include <log/log.h>
 #include <system/window.h>
 #include <ui/BufferHubBuffer.h>
-#include <ui/DetachedBufferHandle.h>
 
 namespace android {
 
@@ -276,14 +275,10 @@
               status_or_handle.error());
         return BAD_VALUE;
     }
-    std::unique_ptr<DetachedBufferHandle> handle =
-            DetachedBufferHandle::Create(status_or_handle.take());
-    if (!handle->isValid()) {
-        ALOGE("detachBuffer: Failed to create a DetachedBufferHandle at slot %zu.", slot);
-        return BAD_VALUE;
-    }
 
-    return graphic_buffer->setDetachedBufferHandle(std::move(handle));
+    // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
+    // be directly backed by BufferHub.
+    return INVALID_OPERATION;
 }
 
 status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) {
@@ -373,7 +368,7 @@
         ALOGE("attachBuffer: out_slot cannot be NULL.");
         return BAD_VALUE;
     }
-    if (buffer == nullptr || !buffer->isDetachedBuffer()) {
+    if (buffer == nullptr) {
         ALOGE("attachBuffer: invalid GraphicBuffer.");
         return BAD_VALUE;
     }
@@ -394,45 +389,9 @@
         return BAD_VALUE;
     }
 
-    // Creates a BufferProducer from the GraphicBuffer.
-    std::unique_ptr<DetachedBufferHandle> detached_handle = buffer->takeDetachedBufferHandle();
-    if (detached_handle == nullptr) {
-        ALOGE("attachBuffer: DetachedBufferHandle cannot be NULL.");
-        return BAD_VALUE;
-    }
-    std::shared_ptr<BufferProducer> buffer_producer =
-            BufferProducer::Import(std::move(detached_handle->handle()));
-    if (buffer_producer == nullptr) {
-        ALOGE("attachBuffer: Failed to import BufferProducer.");
-        return BAD_VALUE;
-    }
-
-    // Adds the BufferProducer into the Queue.
-    auto status_or_slot = queue_->InsertBuffer(buffer_producer);
-    if (!status_or_slot.ok()) {
-        ALOGE("attachBuffer: Failed to insert buffer, error=%d.", status_or_slot.error());
-        return BAD_VALUE;
-    }
-
-    size_t slot = status_or_slot.get();
-    ALOGV("attachBuffer: returning slot %zu.", slot);
-    if (slot >= static_cast<size_t>(max_buffer_count_)) {
-        ALOGE("attachBuffer: Invalid slot: %zu.", slot);
-        return BAD_VALUE;
-    }
-
-    // The just attached buffer should be in dequeued state according to IGraphicBufferProducer
-    // interface. In BufferHub's language the buffer should be in Gained state.
-    buffers_[slot].mGraphicBuffer = buffer;
-    buffers_[slot].mBufferState.attachProducer();
-    buffers_[slot].mEglFence = EGL_NO_SYNC_KHR;
-    buffers_[slot].mFence = Fence::NO_FENCE;
-    buffers_[slot].mRequestBufferCalled = true;
-    buffers_[slot].mAcquireCalled = false;
-    buffers_[slot].mNeedsReallocation = false;
-
-    *out_slot = static_cast<int>(slot);
-    return NO_ERROR;
+    // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
+    // be directly backed by BufferHub.
+    return INVALID_OPERATION;
 }
 
 status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input,
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index f99bc53..69e5379 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -103,11 +103,15 @@
     }
 
     virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
-                                   Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-                                   bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+                                   const ui::Dataspace reqDataspace,
+                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                   uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                                   ISurfaceComposer::Rotation rotation) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
+        data.writeInt32(static_cast<int32_t>(reqDataspace));
+        data.writeInt32(static_cast<int32_t>(reqPixelFormat));
         data.write(sourceCrop);
         data.writeUint32(reqWidth);
         data.writeUint32(reqHeight);
@@ -126,15 +130,19 @@
 
         *outBuffer = new GraphicBuffer();
         reply.read(**outBuffer);
+
         return result;
     }
 
     virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
-                                   sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+                                   sp<GraphicBuffer>* outBuffer, const ui::Dataspace reqDataspace,
+                                   const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
                                    float frameScale, bool childrenOnly) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(layerHandleBinder);
+        data.writeInt32(static_cast<int32_t>(reqDataspace));
+        data.writeInt32(static_cast<int32_t>(reqPixelFormat));
         data.write(sourceCrop);
         data.writeFloat(frameScale);
         data.writeBool(childrenOnly);
@@ -148,6 +156,7 @@
             ALOGE("captureLayers failed to readInt32: %d", result);
             return result;
         }
+
         *outBuffer = new GraphicBuffer();
         reply.read(**outBuffer);
 
@@ -556,8 +565,10 @@
         return reply.readParcelableVector(outLayers);
     }
 
-    virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
-                                              ui::PixelFormat* pixelFormat) const {
+    virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+                                              ui::PixelFormat* defaultPixelFormat,
+                                              ui::Dataspace* wideColorGamutDataspace,
+                                              ui::PixelFormat* wideColorGamutPixelFormat) const {
         Parcel data, reply;
         status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (error != NO_ERROR) {
@@ -569,11 +580,25 @@
         }
         error = static_cast<status_t>(reply.readInt32());
         if (error == NO_ERROR) {
-            *dataSpace = static_cast<ui::Dataspace>(reply.readInt32());
-            *pixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
+            *defaultDataspace = static_cast<ui::Dataspace>(reply.readInt32());
+            *defaultPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
+            *wideColorGamutDataspace = static_cast<ui::Dataspace>(reply.readInt32());
+            *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
         }
         return error;
     }
+
+    virtual status_t getColorManagement(bool* outGetColorManagement) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::GET_COLOR_MANAGEMENT, data, &reply);
+        bool result;
+        status_t err = reply.readBool(&result);
+        if (err == NO_ERROR) {
+            *outGetColorManagement = result;
+        }
+        return err;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -609,10 +634,10 @@
             if (count > data.dataSize()) {
                 return BAD_VALUE;
             }
-            ComposerState s;
             Vector<ComposerState> state;
             state.setCapacity(count);
             for (size_t i = 0; i < count; i++) {
+                ComposerState s;
                 if (s.read(data) == BAD_VALUE) {
                     return BAD_VALUE;
                 }
@@ -645,6 +670,8 @@
         case CAPTURE_SCREEN: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> display = data.readStrongBinder();
+            ui::Dataspace reqDataspace = static_cast<ui::Dataspace>(data.readInt32());
+            ui::PixelFormat reqPixelFormat = static_cast<ui::PixelFormat>(data.readInt32());
             sp<GraphicBuffer> outBuffer;
             Rect sourceCrop(Rect::EMPTY_RECT);
             data.read(sourceCrop);
@@ -653,8 +680,8 @@
             bool useIdentityTransform = static_cast<bool>(data.readInt32());
             int32_t rotation = data.readInt32();
 
-            status_t res = captureScreen(display, &outBuffer, sourceCrop, reqWidth, reqHeight,
-                                         useIdentityTransform,
+            status_t res = captureScreen(display, &outBuffer, reqDataspace, reqPixelFormat,
+                                         sourceCrop, reqWidth, reqHeight, useIdentityTransform,
                                          static_cast<ISurfaceComposer::Rotation>(rotation));
             reply->writeInt32(res);
             if (res == NO_ERROR) {
@@ -665,14 +692,16 @@
         case CAPTURE_LAYERS: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> layerHandleBinder = data.readStrongBinder();
+            ui::Dataspace reqDataspace = static_cast<ui::Dataspace>(data.readInt32());
+            ui::PixelFormat reqPixelFormat = static_cast<ui::PixelFormat>(data.readInt32());
             sp<GraphicBuffer> outBuffer;
             Rect sourceCrop(Rect::EMPTY_RECT);
             data.read(sourceCrop);
             float frameScale = data.readFloat();
             bool childrenOnly = data.readBool();
 
-            status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale,
-                                         childrenOnly);
+            status_t res = captureLayers(layerHandleBinder, &outBuffer, reqDataspace,
+                                         reqPixelFormat, sourceCrop, frameScale, childrenOnly);
             reply->writeInt32(res);
             if (res == NO_ERROR) {
                 reply->write(*outBuffer);
@@ -897,16 +926,31 @@
         }
         case GET_COMPOSITION_PREFERENCE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            ui::Dataspace dataSpace;
-            ui::PixelFormat pixelFormat;
-            status_t error = getCompositionPreference(&dataSpace, &pixelFormat);
+            ui::Dataspace defaultDataspace;
+            ui::PixelFormat defaultPixelFormat;
+            ui::Dataspace wideColorGamutDataspace;
+            ui::PixelFormat wideColorGamutPixelFormat;
+            status_t error =
+                    getCompositionPreference(&defaultDataspace, &defaultPixelFormat,
+                                             &wideColorGamutDataspace, &wideColorGamutPixelFormat);
             reply->writeInt32(error);
             if (error == NO_ERROR) {
-                reply->writeInt32(static_cast<int32_t>(dataSpace));
-                reply->writeInt32(static_cast<int32_t>(pixelFormat));
+                reply->writeInt32(static_cast<int32_t>(defaultDataspace));
+                reply->writeInt32(static_cast<int32_t>(defaultPixelFormat));
+                reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
+                reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
             }
             return NO_ERROR;
         }
+        case GET_COLOR_MANAGEMENT: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            bool result;
+            status_t error = getColorManagement(&result);
+            if (error == NO_ERROR) {
+                reply->writeBool(result);
+            }
+            return result;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
new file mode 100644
index 0000000..95b1038
--- /dev/null
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ITransactionCompletedListener"
+//#define LOG_NDEBUG 0
+
+#include <gui/ITransactionCompletedListener.h>
+
+namespace android {
+
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+    ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION,
+    LAST = ON_TRANSACTION_COMPLETED,
+};
+
+} // Anonymous namespace
+
+status_t SurfaceStats::writeToParcel(Parcel* output) const {
+    status_t err = output->writeStrongBinder(surfaceControl);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    err = output->writeInt64(acquireTime);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    return output->writeBool(releasePreviousBuffer);
+}
+
+status_t SurfaceStats::readFromParcel(const Parcel* input) {
+    status_t err = input->readStrongBinder(&surfaceControl);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    err = input->readInt64(&acquireTime);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    return input->readBool(&releasePreviousBuffer);
+}
+
+status_t TransactionStats::writeToParcel(Parcel* output) const {
+    status_t err = output->writeInt64(latchTime);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    err = output->writeInt64(presentTime);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    return output->writeParcelableVector(surfaceStats);
+}
+
+status_t TransactionStats::readFromParcel(const Parcel* input) {
+    status_t err = input->readInt64(&latchTime);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    err = input->readInt64(&presentTime);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    return input->readParcelableVector(&surfaceStats);
+}
+
+status_t ListenerStats::writeToParcel(Parcel* output) const {
+    status_t err = output->writeInt32(static_cast<int32_t>(transactionStats.size()));
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    for (const auto& [callbackIds, stats] : transactionStats) {
+        err = output->writeParcelable(stats);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        err = output->writeInt64Vector(callbackIds);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t ListenerStats::readFromParcel(const Parcel* input) {
+    int32_t transactionStats_size = input->readInt32();
+
+    for (int i = 0; i < transactionStats_size; i++) {
+        TransactionStats stats;
+        std::vector<CallbackId> callbackIds;
+
+        status_t err = input->readParcelable(&stats);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        err = input->readInt64Vector(&callbackIds);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        transactionStats.emplace(callbackIds, stats);
+    }
+    return NO_ERROR;
+}
+
+ListenerStats ListenerStats::createEmpty(const sp<ITransactionCompletedListener>& listener,
+                                         const std::unordered_set<CallbackId>& callbackIds) {
+    ListenerStats listenerStats;
+    listenerStats.listener = listener;
+    TransactionStats transactionStats;
+    listenerStats.transactionStats.emplace(std::piecewise_construct,
+                                           std::forward_as_tuple(callbackIds.begin(),
+                                                                 callbackIds.end()),
+                                           std::forward_as_tuple(transactionStats));
+    return listenerStats;
+}
+
+class BpTransactionCompletedListener : public SafeBpInterface<ITransactionCompletedListener> {
+public:
+    explicit BpTransactionCompletedListener(const sp<IBinder>& impl)
+          : SafeBpInterface<ITransactionCompletedListener>(impl, "BpTransactionCompletedListener") {
+    }
+
+    ~BpTransactionCompletedListener() override;
+
+    void onTransactionCompleted(ListenerStats stats) override {
+        callRemoteAsync<decltype(&ITransactionCompletedListener::
+                                         onTransactionCompleted)>(Tag::ON_TRANSACTION_COMPLETED,
+                                                                  stats);
+    }
+};
+
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpTransactionCompletedListener::~BpTransactionCompletedListener() = default;
+
+IMPLEMENT_META_INTERFACE(TransactionCompletedListener, "android.gui.ITransactionComposerListener");
+
+status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& data,
+                                                    Parcel* reply, uint32_t flags) {
+    if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+    auto tag = static_cast<Tag>(code);
+    switch (tag) {
+        case Tag::ON_TRANSACTION_COMPLETED:
+            return callLocalAsync(data, reply,
+                                  &ITransactionCompletedListener::onTransactionCompleted);
+    }
+}
+
+}; // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 2b0a461..7b71b39 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -80,6 +80,13 @@
     memcpy(output.writeInplace(16 * sizeof(float)),
            colorTransform.asArray(), 16 * sizeof(float));
 
+    if (output.writeVectorSize(listenerCallbacks) == NO_ERROR) {
+        for (const auto& [listener, callbackIds] : listenerCallbacks) {
+            output.writeStrongBinder(IInterface::asBinder(listener));
+            output.writeInt64Vector(callbackIds);
+        }
+    }
+
     return NO_ERROR;
 }
 
@@ -135,6 +142,14 @@
 
     colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
 
+    int32_t listenersSize = input.readInt32();
+    for (int32_t i = 0; i < listenersSize; i++) {
+        auto listener = interface_cast<ITransactionCompletedListener>(input.readStrongBinder());
+        std::vector<CallbackId> callbackIds;
+        input.readInt64Vector(&callbackIds);
+        listenerCallbacks.emplace_back(listener, callbackIds);
+    }
+
     return NO_ERROR;
 }
 
@@ -323,6 +338,10 @@
         what |= eColorTransformChanged;
         colorTransform = other.colorTransform;
     }
+    if (other.what & eListenerCallbacksChanged) {
+        what |= eListenerCallbacksChanged;
+        listenerCallbacks = other.listenerCallbacks;
+    }
 
     if ((other.what & what) != other.what) {
         ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 1ac9609..e10bda4 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -25,7 +25,9 @@
 #include <utils/String8.h>
 #include <utils/threads.h>
 
+#include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 
 #include <system/graphics.h>
 
@@ -98,6 +100,61 @@
 
 // ---------------------------------------------------------------------------
 
+// TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs
+// to be able to return a sp<> to its instance to pass to SurfaceFlinger.
+// ANDROID_SINGLETON_STATIC_INSTANCE only allows a reference to an instance.
+
+// 0 is an invalid callback id
+TransactionCompletedListener::TransactionCompletedListener() : mCallbackIdCounter(1) {}
+
+CallbackId TransactionCompletedListener::getNextIdLocked() {
+    return mCallbackIdCounter++;
+}
+
+sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
+    static sp<TransactionCompletedListener> sInstance = new TransactionCompletedListener;
+    return sInstance;
+}
+
+sp<ITransactionCompletedListener> TransactionCompletedListener::getIInstance() {
+    return static_cast<sp<ITransactionCompletedListener>>(getInstance());
+}
+
+void TransactionCompletedListener::startListeningLocked() {
+    if (mListening) {
+        return;
+    }
+    ProcessState::self()->startThreadPool();
+    mListening = true;
+}
+
+CallbackId TransactionCompletedListener::addCallback(const TransactionCompletedCallback& callback) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    startListeningLocked();
+
+    CallbackId callbackId = getNextIdLocked();
+    mCallbacks.emplace(callbackId, callback);
+    return callbackId;
+}
+
+void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
+    std::lock_guard lock(mMutex);
+
+    for (const auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
+        for (auto callbackId : callbackIds) {
+            const auto& callback = mCallbacks[callbackId];
+            if (!callback) {
+                ALOGE("cannot call null callback function, skipping");
+                continue;
+            }
+            callback(transactionStats);
+            mCallbacks.erase(callbackId);
+        }
+    }
+}
+
+// ---------------------------------------------------------------------------
+
 SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
     mForceSynchronous(other.mForceSynchronous),
     mTransactionNestCount(other.mTransactionNestCount),
@@ -127,6 +184,17 @@
     }
     other.mDisplayStates.clear();
 
+    for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) {
+        auto& [callbackIds, surfaceControls] = callbackInfo;
+        mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator(
+                                                                callbackIds.begin()),
+                                                        std::make_move_iterator(callbackIds.end()));
+        mListenerCallbacks[listener]
+                .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()),
+                                        std::make_move_iterator(surfaceControls.end()));
+    }
+    other.mListenerCallbacks.clear();
+
     return *this;
 }
 
@@ -137,6 +205,32 @@
 
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
 
+    // For every listener with registered callbacks
+    for (const auto& [listener, callbackInfo] : mListenerCallbacks) {
+        auto& [callbackIds, surfaceControls] = callbackInfo;
+        if (callbackIds.empty()) {
+            continue;
+        }
+
+        // If the listener does not have any SurfaceControls set on this Transaction, send the
+        // callback now
+        if (surfaceControls.empty()) {
+            listener->onTransactionCompleted(ListenerStats::createEmpty(listener, callbackIds));
+        }
+
+        // If the listener has any SurfaceControls set on this Transaction update the surface state
+        for (const auto& surfaceControl : surfaceControls) {
+            layer_state_t* s = getLayerState(surfaceControl);
+            if (!s) {
+                ALOGE("failed to get layer state");
+                continue;
+            }
+            s->what |= layer_state_t::eListenerCallbacksChanged;
+            s->listenerCallbacks.emplace_back(listener, std::move(callbackIds));
+        }
+    }
+    mListenerCallbacks.clear();
+
     Vector<ComposerState> composerStates;
     Vector<DisplayState> displayStates;
     uint32_t flags = 0;
@@ -206,6 +300,11 @@
     return &(mComposerStates[sc].state);
 }
 
+void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(
+        const sp<SurfaceControl>& sc) {
+    mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls.insert(sc);
+}
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
         const sp<SurfaceControl>& sc, float x, float y) {
     layer_state_t* s = getLayerState(sc);
@@ -216,6 +315,8 @@
     s->what |= layer_state_t::ePositionChanged;
     s->x = x;
     s->y = y;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -240,6 +341,7 @@
     s->w = w;
     s->h = h;
 
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -252,6 +354,8 @@
     }
     s->what |= layer_state_t::eLayerChanged;
     s->z = z;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -264,6 +368,8 @@
     s->what |= layer_state_t::eRelativeLayerChanged;
     s->relativeLayerHandle = relativeTo;
     s->z = z;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -283,6 +389,8 @@
     s->flags &= ~mask;
     s->flags |= (flags & mask);
     s->mask |= mask;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -296,6 +404,8 @@
     }
     s->what |= layer_state_t::eTransparentRegionChanged;
     s->transparentRegion = transparentRegion;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -308,6 +418,8 @@
     }
     s->what |= layer_state_t::eAlphaChanged;
     s->alpha = alpha;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -320,6 +432,8 @@
     }
     s->what |= layer_state_t::eLayerStackChanged;
     s->layerStack = layerStack;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -338,6 +452,8 @@
     matrix.dsdy = dsdy;
     matrix.dtdy = dtdy;
     s->matrix = matrix;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -350,6 +466,8 @@
     }
     s->what |= layer_state_t::eCropChanged_legacy;
     s->crop_legacy = crop;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -365,6 +483,8 @@
     s->what |= layer_state_t::eDeferTransaction_legacy;
     s->barrierHandle_legacy = handle;
     s->frameNumber_legacy = frameNumber;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -380,6 +500,8 @@
     s->what |= layer_state_t::eDeferTransaction_legacy;
     s->barrierGbp_legacy = barrierSurface->getIGraphicBufferProducer();
     s->frameNumber_legacy = frameNumber;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -393,6 +515,8 @@
     }
     s->what |= layer_state_t::eReparentChildren;
     s->reparentHandle = newParentHandle;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -406,6 +530,8 @@
     }
     s->what |= layer_state_t::eReparent;
     s->parentHandleForChild = newParentHandle;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -419,6 +545,8 @@
     }
     s->what |= layer_state_t::eColorChanged;
     s->color = color;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -431,6 +559,8 @@
     }
     s->what |= layer_state_t::eTransformChanged;
     s->transform = transform;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -444,6 +574,8 @@
     }
     s->what |= layer_state_t::eTransformToDisplayInverseChanged;
     s->transformToDisplayInverse = transformToDisplayInverse;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -456,6 +588,8 @@
     }
     s->what |= layer_state_t::eCropChanged;
     s->crop = crop;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -468,6 +602,8 @@
     }
     s->what |= layer_state_t::eBufferChanged;
     s->buffer = buffer;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -480,6 +616,8 @@
     }
     s->what |= layer_state_t::eAcquireFenceChanged;
     s->acquireFence = fence;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -492,6 +630,8 @@
     }
     s->what |= layer_state_t::eDataspaceChanged;
     s->dataspace = dataspace;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -504,6 +644,8 @@
     }
     s->what |= layer_state_t::eHdrMetadataChanged;
     s->hdrMetadata = hdrMetadata;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -516,6 +658,8 @@
     }
     s->what |= layer_state_t::eSurfaceDamageRegionChanged;
     s->surfaceDamageRegion = surfaceDamageRegion;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -528,6 +672,8 @@
     }
     s->what |= layer_state_t::eApiChanged;
     s->api = api;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -540,6 +686,22 @@
     }
     s->what |= layer_state_t::eSidebandStreamChanged;
     s->sidebandStream = sidebandStream;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
+        TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
+    auto listener = TransactionCompletedListener::getInstance();
+
+    auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1);
+
+    CallbackId callbackId = listener->addCallback(callbackWithContext);
+
+    mListenerCallbacks[TransactionCompletedListener::getIInstance()].callbackIds.emplace(
+            callbackId);
     return *this;
 }
 
@@ -550,6 +712,8 @@
         mStatus = BAD_INDEX;
     }
     s->what |= layer_state_t::eDetachChildren;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -577,6 +741,8 @@
 
     s->what |= layer_state_t::eOverrideScalingModeChanged;
     s->overrideScalingMode = overrideScalingMode;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -588,6 +754,8 @@
         return *this;
     }
     s->what |= layer_state_t::eGeometryAppliesWithResize;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -611,6 +779,8 @@
     }
     s->what |= layer_state_t::eColorTransformChanged;
     s->colorTransform = mat4(matrix, translation);
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -866,9 +1036,12 @@
     ComposerService::getComposerService()->setPowerMode(token, mode);
 }
 
-status_t SurfaceComposerClient::getCompositionPreference(ui::Dataspace* dataSpace,
-                                                         ui::PixelFormat* pixelFormat) {
-    return ComposerService::getComposerService()->getCompositionPreference(dataSpace, pixelFormat);
+status_t SurfaceComposerClient::getCompositionPreference(
+        ui::Dataspace* defaultDataspace, ui::PixelFormat* defaultPixelFormat,
+        ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) {
+    return ComposerService::getComposerService()
+            ->getCompositionPreference(defaultDataspace, defaultPixelFormat,
+                                       wideColorGamutDataspace, wideColorGamutPixelFormat);
 }
 
 status_t SurfaceComposerClient::clearAnimationFrameStats() {
@@ -887,13 +1060,14 @@
 
 // ----------------------------------------------------------------------------
 
-status_t ScreenshotClient::capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
-                                   uint32_t reqHeight, bool useIdentityTransform, uint32_t rotation,
-                                   sp<GraphicBuffer>* outBuffer) {
+status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                   uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                                   uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
-    status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight,
-                                    useIdentityTransform,
+    status_t ret = s->captureScreen(display, outBuffer, reqDataSpace, reqPixelFormat, sourceCrop,
+                                    reqWidth, reqHeight, useIdentityTransform,
                                     static_cast<ISurfaceComposer::Rotation>(rotation));
     if (ret != NO_ERROR) {
         return ret;
@@ -901,21 +1075,25 @@
     return ret;
 }
 
-status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
+                                         const ui::Dataspace reqDataSpace,
+                                         const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                          float frameScale, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
-    status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
-                                    false /* childrenOnly */);
+    status_t ret = s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat,
+                                    sourceCrop, frameScale, false /* childrenOnly */);
     return ret;
 }
 
-status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle,
+                                              const ui::Dataspace reqDataSpace,
+                                              const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                               float frameScale, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
-    status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
-                                    true /* childrenOnly */);
+    status_t ret = s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat,
+                                    sourceCrop, frameScale, true /* childrenOnly */);
     return ret;
 }
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index a55cfe0..761f31a 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -180,6 +180,36 @@
      * The subregion can be optionally rotated.  It will also be scaled to
      * match the size of the output buffer.
      *
+     * reqDataspace and reqPixelFormat specify the data space and pixel format
+     * of the buffer. The caller should pick the data space and pixel format
+     * that it can consume.
+     *
+     * At the moment, sourceCrop is ignored and is always set to the visible
+     * region (projected display viewport) of the screen.
+     *
+     * reqWidth and reqHeight specifies the size of the buffer.  When either
+     * of them is 0, they are set to the size of the logical display viewport.
+     *
+     * When useIdentityTransform is true, layer transformations are disabled.
+     *
+     * rotation specifies the rotation of the source crop (and the pixels in
+     * it) around its center.
+     */
+    virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
+                                   const ui::Dataspace reqDataspace,
+                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                   uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                                   Rotation rotation = eRotateNone) = 0;
+    /**
+     * Capture the specified screen. This requires READ_FRAME_BUFFER
+     * permission.  This function will fail if there is a secure window on
+     * screen.
+     *
+     * This function can capture a subregion (the source crop) of the screen
+     * into an sRGB buffer with RGBA_8888 pixel format.
+     * The subregion can be optionally rotated.  It will also be scaled to
+     * match the size of the output buffer.
+     *
      * At the moment, sourceCrop is ignored and is always set to the visible
      * region (projected display viewport) of the screen.
      *
@@ -193,15 +223,34 @@
      */
     virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
                                    Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-                                   bool useIdentityTransform, Rotation rotation = eRotateNone) = 0;
+                                   bool useIdentityTransform, Rotation rotation = eRotateNone) {
+        return captureScreen(display, outBuffer, ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
+                             sourceCrop, reqWidth, reqHeight, useIdentityTransform, rotation);
+    }
 
     /**
      * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
+     *
+     * reqDataspace and reqPixelFormat specify the data space and pixel format
+     * of the buffer. The caller should pick the data space and pixel format
+     * that it can consume.
      */
     virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
-                                   sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+                                   sp<GraphicBuffer>* outBuffer, const ui::Dataspace reqDataspace,
+                                   const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
                                    float frameScale = 1.0, bool childrenOnly = false) = 0;
 
+    /**
+     * Capture a subtree of the layer hierarchy into an sRGB buffer with RGBA_8888 pixel format,
+     * potentially ignoring the root node.
+     */
+    status_t captureLayers(const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer,
+                           const Rect& sourceCrop, float frameScale = 1.0,
+                           bool childrenOnly = false) {
+        return captureLayers(layerHandleBinder, outBuffer, ui::Dataspace::V0_SRGB,
+                             ui::PixelFormat::RGBA_8888, sourceCrop, frameScale, childrenOnly);
+    }
+
     /* Clears the frame statistics for animations.
      *
      * Requires the ACCESS_SURFACE_FLINGER permission.
@@ -231,8 +280,19 @@
      */
     virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0;
 
-    virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
-                                              ui::PixelFormat* pixelFormat) const = 0;
+    virtual status_t getColorManagement(bool* outGetColorManagement) const = 0;
+
+    /* Gets the composition preference of the default data space and default pixel format,
+     * as well as the wide color gamut data space and wide color gamut pixel format.
+     * If the wide color gamut data space is V0_SRGB, then it implies that the platform
+     * has no wide color gamut support.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+                                              ui::PixelFormat* defaultPixelFormat,
+                                              ui::Dataspace* wideColorGamutDataspace,
+                                              ui::PixelFormat* wideColorGamutPixelFormat) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -271,6 +331,7 @@
         GET_LAYER_DEBUG_INFO,
         CREATE_SCOPED_CONNECTION,
         GET_COMPOSITION_PREFERENCE,
+        GET_COLOR_MANAGEMENT,
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
new file mode 100644
index 0000000..5c41c21
--- /dev/null
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/SafeInterface.h>
+
+#include <utils/Timers.h>
+
+#include <cstdint>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace android {
+
+class ITransactionCompletedListener;
+
+using CallbackId = int64_t;
+
+struct CallbackIdsHash {
+    // CallbackId vectors have several properties that let us get away with this simple hash.
+    // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is
+    // empty we can still hash 0.
+    // 2) CallbackId vectors for the same listener either are identical or contain none of the
+    // same members. It is sufficient to just check the first CallbackId in the vectors. If
+    // they match, they are the same. If they do not match, they are not the same.
+    std::size_t operator()(const std::vector<CallbackId> callbackIds) const {
+        return std::hash<CallbackId>{}((callbackIds.size() == 0) ? 0 : callbackIds.front());
+    }
+};
+
+class SurfaceStats : public Parcelable {
+public:
+    status_t writeToParcel(Parcel* output) const override;
+    status_t readFromParcel(const Parcel* input) override;
+
+    SurfaceStats() = default;
+    SurfaceStats(const sp<IBinder>& sc, nsecs_t time, bool releasePrevBuffer)
+          : surfaceControl(sc), acquireTime(time), releasePreviousBuffer(releasePrevBuffer) {}
+
+    sp<IBinder> surfaceControl;
+    nsecs_t acquireTime = -1;
+    bool releasePreviousBuffer = false;
+};
+
+class TransactionStats : public Parcelable {
+public:
+    status_t writeToParcel(Parcel* output) const override;
+    status_t readFromParcel(const Parcel* input) override;
+
+    nsecs_t latchTime = -1;
+    nsecs_t presentTime = -1;
+    std::vector<SurfaceStats> surfaceStats;
+};
+
+class ListenerStats : public Parcelable {
+public:
+    status_t writeToParcel(Parcel* output) const override;
+    status_t readFromParcel(const Parcel* input) override;
+
+    static ListenerStats createEmpty(const sp<ITransactionCompletedListener>& listener,
+                                     const std::unordered_set<CallbackId>& callbackIds);
+
+    sp<ITransactionCompletedListener> listener;
+    std::unordered_map<std::vector<CallbackId>, TransactionStats, CallbackIdsHash> transactionStats;
+};
+
+class ITransactionCompletedListener : public IInterface {
+public:
+    DECLARE_META_INTERFACE(TransactionCompletedListener)
+
+    virtual void onTransactionCompleted(ListenerStats stats) = 0;
+};
+
+class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
+public:
+    BnTransactionCompletedListener()
+          : SafeBnInterface<ITransactionCompletedListener>("BnTransactionCompletedListener") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
+};
+
+class ListenerCallbacks {
+public:
+    ListenerCallbacks(const sp<ITransactionCompletedListener>& listener,
+                      const std::unordered_set<CallbackId>& callbacks)
+          : transactionCompletedListener(listener),
+            callbackIds(callbacks.begin(), callbacks.end()) {}
+
+    ListenerCallbacks(const sp<ITransactionCompletedListener>& listener,
+                      const std::vector<CallbackId>& ids)
+          : transactionCompletedListener(listener), callbackIds(ids) {}
+
+    sp<ITransactionCompletedListener> transactionCompletedListener;
+    std::vector<CallbackId> callbackIds;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index e06e2b1..ddbac7b 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -23,6 +23,7 @@
 #include <utils/Errors.h>
 
 #include <gui/IGraphicBufferProducer.h>
+#include <gui/ITransactionCompletedListener.h>
 #include <math/mat4.h>
 #include <math/vec3.h>
 #include <ui/GraphicTypes.h>
@@ -74,6 +75,7 @@
         eApiChanged = 0x04000000,
         eSidebandStreamChanged = 0x08000000,
         eColorTransformChanged = 0x10000000,
+        eListenerCallbacksChanged = 0x20000000,
     };
 
     layer_state_t()
@@ -154,6 +156,8 @@
     int32_t api;
     sp<NativeHandle> sidebandStream;
     mat4 colorTransform;
+
+    std::vector<ListenerCallbacks> listenerCallbacks;
 };
 
 struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 69a759f..1cafb77 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -19,7 +19,9 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <set>
 #include <unordered_map>
+#include <unordered_set>
 
 #include <binder/IBinder.h>
 
@@ -33,9 +35,10 @@
 #include <ui/PixelFormat.h>
 
 #include <gui/CpuConsumer.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <gui/LayerState.h>
 #include <gui/SurfaceControl.h>
 #include <math/vec3.h>
-#include <gui/LayerState.h>
 
 namespace android {
 
@@ -49,6 +52,37 @@
 
 // ---------------------------------------------------------------------------
 
+using TransactionCompletedCallbackTakesContext =
+        std::function<void(void* /*context*/, const TransactionStats&)>;
+using TransactionCompletedCallback = std::function<void(const TransactionStats&)>;
+
+class TransactionCompletedListener : public BnTransactionCompletedListener {
+    TransactionCompletedListener();
+
+    CallbackId getNextIdLocked() REQUIRES(mMutex);
+
+    std::mutex mMutex;
+
+    bool mListening GUARDED_BY(mMutex) = false;
+
+    CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
+
+    std::map<CallbackId, TransactionCompletedCallback> mCallbacks GUARDED_BY(mMutex);
+
+public:
+    static sp<TransactionCompletedListener> getInstance();
+    static sp<ITransactionCompletedListener> getIInstance();
+
+    void startListeningLocked() REQUIRES(mMutex);
+
+    CallbackId addCallback(const TransactionCompletedCallback& callback);
+
+    // Overrides BnTransactionCompletedListener's onTransactionCompleted
+    void onTransactionCompleted(ListenerStats stats) override;
+};
+
+// ---------------------------------------------------------------------------
+
 class SurfaceComposerClient : public RefBase
 {
     friend class Composer;
@@ -101,9 +135,15 @@
     /* Triggers screen on/off or low power mode and waits for it to complete */
     static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
 
-    //
-    static status_t getCompositionPreference(ui::Dataspace* dataSpace,
-                                             ui::PixelFormat* pixelFormat);
+    /* Returns the composition preference of the default data space and default pixel format,
+     * as well as the wide color gamut data space and wide color gamut pixel format.
+     * If the wide color gamut data space is V0_SRGB, then it implies that the platform
+     * has no wide color gamut support.
+     */
+    static status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+                                             ui::PixelFormat* defaultPixelFormat,
+                                             ui::Dataspace* wideColorGamutDataspace,
+                                             ui::PixelFormat* wideColorGamutPixelFormat);
 
     // ------------------------------------------------------------------------
     // surface creation / destruction
@@ -152,9 +192,27 @@
         }
     };
 
+    struct TCLHash {
+        std::size_t operator()(const sp<ITransactionCompletedListener>& tcl) const {
+            return std::hash<IBinder*>{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr);
+        }
+    };
+
+    struct CallbackInfo {
+        // All the callbacks that have been requested for a TransactionCompletedListener in the
+        // Transaction
+        std::unordered_set<CallbackId> callbackIds;
+        // All the SurfaceControls that have been modified in this TransactionCompletedListener's
+        // process that require a callback if there is one or more callbackIds set.
+        std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls;
+    };
+
     class Transaction {
         std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
         SortedVector<DisplayState > mDisplayStates;
+        std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
+                mListenerCallbacks;
+
         uint32_t                    mForceSynchronous = 0;
         uint32_t                    mTransactionNestCount = 0;
         bool                        mAnimation = false;
@@ -165,6 +223,8 @@
         layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
         DisplayState& getDisplayState(const sp<IBinder>& token);
 
+        void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
+
     public:
         Transaction() = default;
         virtual ~Transaction() = default;
@@ -244,6 +304,9 @@
         Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
                                        const sp<NativeHandle>& sidebandStream);
 
+        Transaction& addTransactionCompletedCallback(
+                TransactionCompletedCallbackTakesContext callback, void* callbackContext);
+
         // Detaches all child surfaces (and their children recursively)
         // from their SurfaceControl.
         // The child SurfaceControls will not throw exceptions or return errors,
@@ -329,16 +392,21 @@
 public:
     // if cropping isn't required, callers may pass in a default Rect, e.g.:
     //   capture(display, producer, Rect(), reqWidth, ...);
-    static status_t capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
-                            uint32_t reqHeight, bool useIdentityTransform, uint32_t rotation,
-                            sp<GraphicBuffer>* outBuffer);
-    static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float frameScale,
-                                  sp<GraphicBuffer>* outBuffer);
-    static status_t captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+    static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+                            const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                            uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                            uint32_t rotation, sp<GraphicBuffer>* outBuffer);
+    static status_t captureLayers(const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
+                                  const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                  float frameScale, sp<GraphicBuffer>* outBuffer);
+    static status_t captureChildLayers(const sp<IBinder>& layerHandle,
+                                       const ui::Dataspace reqDataSpace,
+                                       const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                        float frameScale, sp<GraphicBuffer>* outBuffer);
 };
 
 // ---------------------------------------------------------------------------
+
 }; // namespace android
 
 #endif // ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 6d03374..aef7aed 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -777,14 +777,6 @@
     ASSERT_OK(mProducer->detachBuffer(slot));
     EXPECT_OK(buffer->initCheck());
 
-    if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
-        // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have
-        // isDetachedBuffer() set. Note that this only applies to BufferHub.
-        EXPECT_TRUE(buffer->isDetachedBuffer());
-    } else {
-        EXPECT_FALSE(buffer->isDetachedBuffer());
-    }
-
     ASSERT_OK(mProducer->disconnect(TEST_API));
 
     ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
@@ -801,16 +793,7 @@
     ASSERT_OK(mProducer->detachBuffer(slot));
     EXPECT_OK(buffer->initCheck());
 
-    if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
-        // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have
-        // isDetachedBuffer() set. Note that this only applies to BufferHub.
-        EXPECT_TRUE(buffer->isDetachedBuffer());
-    } else {
-        EXPECT_FALSE(buffer->isDetachedBuffer());
-    }
-
     EXPECT_OK(mProducer->attachBuffer(&slot, buffer));
-    EXPECT_FALSE(buffer->isDetachedBuffer());
     EXPECT_OK(buffer->initCheck());
 }
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index bc80899..d0600da 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -134,8 +134,9 @@
     sp<IBinder> display(sf->getBuiltInDisplay(
             ISurfaceComposer::eDisplayIdMain));
     sp<GraphicBuffer> outBuffer;
-    ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(),
-            64, 64, false));
+    ASSERT_EQ(NO_ERROR,
+              sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB,
+                                ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false));
 
     ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(),
             NATIVE_WINDOW_API_CPU));
@@ -165,8 +166,9 @@
                 &buf));
         ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
     }
-    ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(),
-            64, 64, false));
+    ASSERT_EQ(NO_ERROR,
+              sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB,
+                                ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false));
 }
 
 TEST_F(SurfaceTest, ConcreteTypeIsSurface) {
@@ -596,14 +598,19 @@
     }
     status_t setActiveColorMode(const sp<IBinder>& /*display*/,
         ColorMode /*colorMode*/) override { return NO_ERROR; }
-    status_t captureScreen(const sp<IBinder>& /*display*/,
-            sp<GraphicBuffer>* /*outBuffer*/,
-            Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
-            bool /*useIdentityTransform*/,
-            Rotation /*rotation*/) override { return NO_ERROR; }
+    status_t captureScreen(const sp<IBinder>& /*display*/, sp<GraphicBuffer>* /*outBuffer*/,
+                           const ui::Dataspace /*reqDataspace*/,
+                           const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/,
+                           uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
+                           bool /*useIdentityTransform*/, Rotation /*rotation*/) override {
+        return NO_ERROR;
+    }
     virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
-                                   sp<GraphicBuffer>* /*outBuffer*/, const Rect& /*sourceCrop*/,
-                                   float /*frameScale*/, bool /*childrenOnly*/) override {
+                                   sp<GraphicBuffer>* /*outBuffer*/,
+                                   const ui::Dataspace /*reqDataspace*/,
+                                   const ui::PixelFormat /*reqPixelFormat*/,
+                                   const Rect& /*sourceCrop*/, float /*frameScale*/,
+                                   bool /*childrenOnly*/) override {
         return NO_ERROR;
     }
     status_t clearAnimationFrameStats() override { return NO_ERROR; }
@@ -621,11 +628,15 @@
     status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override {
         return NO_ERROR;
     }
-    status_t getCompositionPreference(ui::Dataspace* /*outDataSpace*/,
-                                      ui::PixelFormat* /*outPixelFormat*/) const override {
+    status_t getCompositionPreference(
+            ui::Dataspace* /*outDefaultDataspace*/, ui::PixelFormat* /*outDefaultPixelFormat*/,
+            ui::Dataspace* /*outWideColorGamutDataspace*/,
+            ui::PixelFormat* /*outWideColorGamutPixelFormat*/) const override {
         return NO_ERROR;
     }
 
+    virtual status_t getColorManagement(bool* /*outGetColorManagement*/) const { return NO_ERROR; }
+
 protected:
     IBinder* onAsBinder() override { return nullptr; }
 
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 5fbb3b2..fba319d 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -13,13 +13,20 @@
 // limitations under the License.
 
 ndk_headers {
-    name: "libnativewindow_headers",
+    name: "libnativewindow_ndk_headers",
     from: "include/android",
     to: "android",
     srcs: ["include/android/*.h"],
     license: "NOTICE",
 }
 
+// TODO(b/118715870): cleanup header files
+cc_library_headers {
+    name: "libnativewindow_headers",
+    export_include_dirs: ["include"],
+    vendor_available: false,
+}
+
 ndk_library {
     name: "libnativewindow",
     symbol_file: "libnativewindow.map.txt",
@@ -40,6 +47,7 @@
     cflags: [
         "-Wall",
         "-Werror",
+        "-Wno-enum-compare",
         "-Wno-unused-function",
     ],
 
@@ -70,6 +78,7 @@
 
     header_libs: [
         "libnativebase_headers",
+        "libnativewindow_headers",
     ],
 
     // headers we include in our public headers
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 9ca4941..23ac60b 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -15,12 +15,31 @@
  */
 
 /**
- * @addtogroup NativeActivity Native Activity
- * @{
- */
-
-/**
  * @file hardware_buffer.h
+ * @brief API for native hardware buffers.
+ */
+/**
+ * @defgroup AHardwareBuffer Native Hardware Buffer
+ *
+ * AHardwareBuffer objects represent chunks of memory that can be
+ * accessed by various hardware components in the system. It can be
+ * easily converted to the Java counterpart
+ * android.hardware.HardwareBuffer and passed between processes using
+ * Binder. All operations involving AHardwareBuffer and HardwareBuffer
+ * are zero-copy, i.e., passing AHardwareBuffer to another process
+ * creates a shared view of the same region of memory.
+ *
+ * AHardwareBuffers can be bound to EGL/OpenGL and Vulkan primitives.
+ * For EGL, use the extension function eglGetNativeClientBufferANDROID
+ * to obtain an EGLClientBuffer and pass it directly to
+ * eglCreateImageKHR. Refer to the EGL extensions
+ * EGL_ANDROID_get_native_client_buffer and
+ * EGL_ANDROID_image_native_buffer for more information. In Vulkan,
+ * the contents of the AHardwareBuffer can be accessed as external
+ * memory. See the VK_ANDROID_external_memory_android_hardware_buffer
+ * extension for details.
+ *
+ * @{
  */
 
 #ifndef ANDROID_HARDWARE_BUFFER_H
@@ -37,7 +56,7 @@
 /**
  * Buffer pixel formats.
  */
-enum {
+enum AHardwareBuffer_Format {
     /**
      * Corresponding formats:
      *   Vulkan: VK_FORMAT_R8G8B8A8_UNORM
@@ -134,27 +153,47 @@
 /**
  * Buffer usage flags, specifying how the buffer will be accessed.
  */
-enum {
-    /// The buffer will never be read by the CPU.
+enum AHardwareBuffer_UsageFlags {
+    /// The buffer will never be locked for direct CPU reads using the
+    /// AHardwareBuffer_lock() function. Note that reading the buffer
+    /// using OpenGL or Vulkan functions or memory mappings is still
+    /// allowed.
     AHARDWAREBUFFER_USAGE_CPU_READ_NEVER        = 0UL,
-    /// The buffer will sometimes be read by the CPU.
+    /// The buffer will sometimes be locked for direct CPU reads using
+    /// the AHardwareBuffer_lock() function. Note that reading the
+    /// buffer using OpenGL or Vulkan functions or memory mappings
+    /// does not require the presence of this flag.
     AHARDWAREBUFFER_USAGE_CPU_READ_RARELY       = 2UL,
-    /// The buffer will often be read by the CPU.
+    /// The buffer will often be locked for direct CPU reads using
+    /// the AHardwareBuffer_lock() function. Note that reading the
+    /// buffer using OpenGL or Vulkan functions or memory mappings
+    /// does not require the presence of this flag.
     AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN        = 3UL,
     /// CPU read value mask.
     AHARDWAREBUFFER_USAGE_CPU_READ_MASK         = 0xFUL,
 
-    /// The buffer will never be written by the CPU.
+    /// The buffer will never be locked for direct CPU writes using the
+    /// AHardwareBuffer_lock() function. Note that writing the buffer
+    /// using OpenGL or Vulkan functions or memory mappings is still
+    /// allowed.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER       = 0UL << 4,
-    /// The buffer will sometimes be written to by the CPU.
+    /// The buffer will sometimes be locked for direct CPU writes using
+    /// the AHardwareBuffer_lock() function. Note that writing the
+    /// buffer using OpenGL or Vulkan functions or memory mappings
+    /// does not require the presence of this flag.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY      = 2UL << 4,
-    /// The buffer will often be written to by the CPU.
+    /// The buffer will often be locked for direct CPU writes using
+    /// the AHardwareBuffer_lock() function. Note that writing the
+    /// buffer using OpenGL or Vulkan functions or memory mappings
+    /// does not require the presence of this flag.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN       = 3UL << 4,
     /// CPU write value mask.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK        = 0xFUL << 4,
 
     /// The buffer will be read from by the GPU as a texture.
     AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE      = 1UL << 8,
+    /// The buffer will be written to by the GPU as a framebuffer attachment.
+    AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER        = 1UL << 9,
     /**
      * The buffer will be written to by the GPU as a framebuffer attachment.
      * Note that the name of this flag is somewhat misleading: it does not imply
@@ -162,16 +201,33 @@
      * format that will be used as a framebuffer attachment should also have
      * this flag.
      */
-    AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT       = 1UL << 9,
-    /// The buffer must not be used outside of a protected hardware path.
+    AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT       = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
+    /**
+     * The buffer is protected from direct CPU access or being read by non-secure
+     * hardware, such as video encoders. This flag is incompatible with CPU
+     * read and write flags. It is mainly used when handling DRM video.
+     * Refer to the EGL extension EGL_EXT_protected_content and GL extension
+     * EXT_protected_textures for more information on how these buffers are expected
+     * to behave.
+     */
     AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT      = 1UL << 14,
     /// The buffer will be read by a hardware video encoder.
     AHARDWAREBUFFER_USAGE_VIDEO_ENCODE           = 1UL << 16,
-    /// The buffer will be used for direct writes from sensors.
+    /**
+     * The buffer will be used for direct writes from sensors.
+     * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
+     */
     AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA     = 1UL << 23,
-    /// The buffer will be used as a shader storage or uniform buffer object.
+    /**
+     * The buffer will be used as a shader storage or uniform buffer object.
+     * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
+     */
     AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER        = 1UL << 24,
-    /// The buffer will be used as a cube map texture.
+    /**
+     * The buffer will be used as a cube map texture.
+     * When this flag is present, the buffer must have a layer count that is
+     * a multiple of 6.
+     */
     AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP               = 1UL << 25,
     /// The buffer contains a complete mipmap hierarchy.
     AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE        = 1UL << 26,
@@ -206,20 +262,27 @@
     uint32_t    width;      ///< Width in pixels.
     uint32_t    height;     ///< Height in pixels.
     uint32_t    layers;     ///< Number of images in an image array.
-    uint32_t    format;     ///< One of AHARDWAREBUFFER_FORMAT_*
-    uint64_t    usage;      ///< Combination of AHARDWAREBUFFER_USAGE_*
+    uint32_t    format;     ///< One of AHardwareBuffer_Format.
+    uint64_t    usage;      ///< Combination of AHardwareBuffer_UsageFlags.
     uint32_t    stride;     ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
     uint32_t    rfu0;       ///< Initialize to zero, reserved for future use.
     uint64_t    rfu1;       ///< Initialize to zero, reserved for future use.
 } AHardwareBuffer_Desc;
 
+/**
+ * Opaque handle for a native hardware buffer.
+ */
 typedef struct AHardwareBuffer AHardwareBuffer;
 
 #if __ANDROID_API__ >= 26
 
 /**
- * Allocates a buffer that backs an AHardwareBuffer using the passed
- * AHardwareBuffer_Desc.
+ * Allocates a buffer that matches the passed AHardwareBuffer_Desc.
+ *
+ * If allocation succeeds, the buffer can be used according to the
+ * usage flags specified in its description. If a buffer is used in ways
+ * not compatible with its usage flags, the results are undefined and
+ * may include program termination.
  *
  * \return 0 on success, or an error number of the allocation fails for
  * any reason. The returned buffer has a reference count of 1.
@@ -234,7 +297,7 @@
 
 /**
  * Remove a reference that was previously acquired with
- * AHardwareBuffer_acquire().
+ * AHardwareBuffer_acquire() or AHardwareBuffer_allocate().
  */
 void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
 
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 6831f91..6730596 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -15,7 +15,13 @@
  */
 
 /**
- * @addtogroup NativeActivity Native Activity
+ * @defgroup ANativeWindow Native Window
+ *
+ * ANativeWindow represents the producer end of an image queue.
+ * It is the C counterpart of the android.view.Surface object in Java,
+ * and can be converted both ways. Depending on the consumer, images
+ * submitted to ANativeWindow can be shown on the display or sent to
+ * other consumers, such as video encoders.
  * @{
  */
 
@@ -41,7 +47,7 @@
  * Legacy window pixel format names, kept for backwards compatibility.
  * New code and APIs should use AHARDWAREBUFFER_FORMAT_*.
  */
-enum {
+enum ANativeWindow_LegacyFormat {
     // NOTE: these values must match the values from graphics/common/x.x/types.hal
 
     /** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/
@@ -95,7 +101,7 @@
     /// memory. This may be >= width.
     int32_t stride;
 
-    /// The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
+    /// The format of the buffer. One of AHardwareBuffer_Format.
     int32_t format;
 
     /// The actual bits.
@@ -151,7 +157,7 @@
  *
  * \param width width of the buffers in pixels.
  * \param height height of the buffers in pixels.
- * \param format one of AHARDWAREBUFFER_FORMAT_* constants.
+ * \param format one of the AHardwareBuffer_Format constants.
  * \return 0 for success, or a negative value on error.
  */
 int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
diff --git a/services/surfaceflinger/RenderEngine/Android.bp b/libs/renderengine/Android.bp
similarity index 93%
rename from services/surfaceflinger/RenderEngine/Android.bp
rename to libs/renderengine/Android.bp
index 79145c2..7efc8bd 100644
--- a/services/surfaceflinger/RenderEngine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -1,4 +1,3 @@
-// TODO(b/112585051) Add to VNDK once moved to libs/
 cc_defaults {
     name: "renderengine_defaults",
     cflags: [
@@ -26,7 +25,7 @@
         "libGLESv2",
         "libgui",
         "liblog",
-    	"libnativewindow",
+        "libnativewindow",
         "libui",
         "libutils",
     ],
@@ -60,8 +59,11 @@
 cc_library_static {
     name: "librenderengine",
     defaults: ["librenderengine_defaults"],
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
     double_loadable: true,
-
     clang: true,
     cflags: [
         "-fvisibility=hidden",
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/libs/renderengine/Description.cpp
similarity index 96%
rename from services/surfaceflinger/RenderEngine/Description.cpp
rename to libs/renderengine/Description.cpp
index 9696d28..b9cea10 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/libs/renderengine/Description.cpp
@@ -52,5 +52,5 @@
     return colorMatrix != identity;
 }
 
-}  // namespace renderengine
-}  // namespace android
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/libs/renderengine/Mesh.cpp
similarity index 97%
rename from services/surfaceflinger/RenderEngine/Mesh.cpp
rename to libs/renderengine/Mesh.cpp
index 809a0d7..6a40c6c 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/libs/renderengine/Mesh.cpp
@@ -91,5 +91,5 @@
     return mStride;
 }
 
-}  // namespace renderengine
-}  // namespace android
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
similarity index 90%
rename from services/surfaceflinger/RenderEngine/RenderEngine.cpp
rename to libs/renderengine/RenderEngine.cpp
index 3b54873..8be1c3c 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -39,8 +39,7 @@
 
 namespace impl {
 
-RenderEngine::RenderEngine(uint32_t featureFlags)
-      : mFeatureFlags(featureFlags) {}
+RenderEngine::RenderEngine(uint32_t featureFlags) : mFeatureFlags(featureFlags) {}
 
 RenderEngine::~RenderEngine() = default;
 
@@ -52,6 +51,6 @@
     return SyncFeatures::getInstance().useWaitSync();
 }
 
-}  // namespace impl
-}  // namespace renderengine
-}  // namespace android
+} // namespace impl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/TEST_MAPPING b/libs/renderengine/TEST_MAPPING
similarity index 100%
rename from services/surfaceflinger/RenderEngine/TEST_MAPPING
rename to libs/renderengine/TEST_MAPPING
diff --git a/services/surfaceflinger/RenderEngine/Texture.cpp b/libs/renderengine/Texture.cpp
similarity index 96%
rename from services/surfaceflinger/RenderEngine/Texture.cpp
rename to libs/renderengine/Texture.cpp
index 5eabbcf..154cde8 100644
--- a/services/surfaceflinger/RenderEngine/Texture.cpp
+++ b/libs/renderengine/Texture.cpp
@@ -73,5 +73,5 @@
     return mHeight;
 }
 
-}  // namespace renderengine
-}  // namespace android
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp b/libs/renderengine/gl/GLES20RenderEngine.cpp
similarity index 89%
rename from services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
rename to libs/renderengine/gl/GLES20RenderEngine.cpp
index dbf50c5..e244a83 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
+++ b/libs/renderengine/gl/GLES20RenderEngine.cpp
@@ -261,7 +261,7 @@
     contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
     contextAttributes.push_back(contextClientVersion);
     bool useContextPriority = extensions.hasContextPriority() &&
-                              (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
+            (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
     if (useContextPriority) {
         contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
         contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
@@ -275,6 +275,8 @@
 
     // now figure out what version of GL did we actually get
     // NOTE: a dummy surface is not needed if KHR_create_context is supported
+    // TODO(alecmouri): don't create this surface if EGL_KHR_surfaceless_context
+    // is supported.
 
     EGLConfig dummyConfig = config;
     if (dummyConfig == EGL_NO_CONFIG) {
@@ -301,10 +303,10 @@
             break;
         case GLES_VERSION_2_0:
         case GLES_VERSION_3_0:
-            engine = std::make_unique<GLES20RenderEngine>(featureFlags);
+            engine = std::make_unique<GLES20RenderEngine>(featureFlags, display, config, ctxt,
+                                                          dummy);
             break;
     }
-    engine->setEGLHandles(display, config, ctxt);
 
     ALOGI("OpenGL ES informations:");
     ALOGI("vendor    : %s", extensions.getVendor());
@@ -314,9 +316,6 @@
     ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
     ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
 
-    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    eglDestroySurface(display, dummy);
-
     return engine;
 }
 
@@ -359,11 +358,13 @@
     return config;
 }
 
-GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags)
+GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
+                                       EGLContext ctxt, EGLSurface dummy)
       : renderengine::impl::RenderEngine(featureFlags),
-        mEGLDisplay(EGL_NO_DISPLAY),
-        mEGLConfig(nullptr),
-        mEGLContext(EGL_NO_CONTEXT),
+        mEGLDisplay(display),
+        mEGLConfig(config),
+        mEGLContext(ctxt),
+        mDummySurface(dummy),
         mVpWidth(0),
         mVpHeight(0),
         mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
@@ -385,17 +386,9 @@
     // mColorBlindnessCorrection = M;
 
     if (mUseColorManagement) {
-        ColorSpace srgb(ColorSpace::sRGB());
-        ColorSpace displayP3(ColorSpace::DisplayP3());
-        ColorSpace bt2020(ColorSpace::BT2020());
-
-        // Compute sRGB to Display P3 transform matrix.
-        // NOTE: For now, we are limiting output wide color space support to
-        // Display-P3 only.
-        mSrgbToDisplayP3 = mat4(ColorSpaceConnector(srgb, displayP3).getTransform());
-
-        // Compute Display P3 to sRGB transform matrix.
-        mDisplayP3ToSrgb = mat4(ColorSpaceConnector(displayP3, srgb).getTransform());
+        const ColorSpace srgb(ColorSpace::sRGB());
+        const ColorSpace displayP3(ColorSpace::DisplayP3());
+        const ColorSpace bt2020(ColorSpace::BT2020());
 
         // no chromatic adaptation needed since all color spaces use D65 for their white points.
         mSrgbToXyz = mat4(srgb.getRGBtoXYZ());
@@ -404,6 +397,20 @@
         mXyzToSrgb = mat4(srgb.getXYZtoRGB());
         mXyzToDisplayP3 = mat4(displayP3.getXYZtoRGB());
         mXyzToBt2020 = mat4(bt2020.getXYZtoRGB());
+
+        // Compute sRGB to Display P3 and BT2020 transform matrix.
+        // NOTE: For now, we are limiting output wide color space support to
+        // Display-P3 and BT2020 only.
+        mSrgbToDisplayP3 = mXyzToDisplayP3 * mSrgbToXyz;
+        mSrgbToBt2020 = mXyzToBt2020 * mSrgbToXyz;
+
+        // Compute Display P3 to sRGB and BT2020 transform matrix.
+        mDisplayP3ToSrgb = mXyzToSrgb * mDisplayP3ToXyz;
+        mDisplayP3ToBt2020 = mXyzToBt2020 * mDisplayP3ToXyz;
+
+        // Compute BT2020 to sRGB and Display P3 transform matrix
+        mBt2020ToSrgb = mXyzToSrgb * mBt2020ToXyz;
+        mBt2020ToDisplayP3 = mXyzToDisplayP3 * mBt2020ToXyz;
     }
 }
 
@@ -589,15 +596,13 @@
     glDeleteTextures(count, names);
 }
 
-void GLES20RenderEngine::bindExternalTextureImage(uint32_t texName,
-                                                  const Image& image) {
+void GLES20RenderEngine::bindExternalTextureImage(uint32_t texName, const Image& image) {
     const GLImage& glImage = static_cast<const GLImage&>(image);
     const GLenum target = GL_TEXTURE_EXTERNAL_OES;
 
     glBindTexture(target, texName);
     if (glImage.getEGLImage() != EGL_NO_IMAGE_KHR) {
-        glEGLImageTargetTexture2DOES(target,
-                                     static_cast<GLeglImageOES>(glImage.getEGLImage()));
+        glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(glImage.getEGLImage()));
     }
 }
 
@@ -613,16 +618,15 @@
 
     // Bind the Framebuffer to render into
     glBindFramebuffer(GL_FRAMEBUFFER, framebufferName);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                           GL_TEXTURE_2D, textureName, 0);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0);
 
     mRenderToFbo = true;
     mFboHeight = glFramebuffer->getBufferHeight();
 
     uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 
-    ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES,
-             "glCheckFramebufferStatusOES error %d", glStatus);
+    ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
+             glStatus);
 
     return glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
 }
@@ -633,12 +637,6 @@
 
     // back to main framebuffer
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
-    // Workaround for b/77935566 to force the EGL driver to release the
-    // screenshot buffer
-    setScissor(Rect::EMPTY_RECT);
-    clearWithColor(0.0, 0.0, 0.0, 0.0);
-    disableScissor();
 }
 
 void GLES20RenderEngine::checkErrors() const {
@@ -790,12 +788,19 @@
         Description managedState = mState;
         Dataspace inputStandard = static_cast<Dataspace>(mDataSpace & Dataspace::STANDARD_MASK);
         Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
-        Dataspace outputStandard = static_cast<Dataspace>(mOutputDataSpace &
-                                                          Dataspace::STANDARD_MASK);
-        Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace &
-                                                          Dataspace::TRANSFER_MASK);
+        Dataspace outputStandard =
+                static_cast<Dataspace>(mOutputDataSpace & Dataspace::STANDARD_MASK);
+        Dataspace outputTransfer =
+                static_cast<Dataspace>(mOutputDataSpace & Dataspace::TRANSFER_MASK);
         bool needsXYZConversion = needsXYZTransformMatrix();
 
+        // NOTE: if the input standard of the input dataspace is not STANDARD_DCI_P3 or
+        // STANDARD_BT2020, it will be  treated as STANDARD_BT709
+        if (inputStandard != Dataspace::STANDARD_DCI_P3 &&
+            inputStandard != Dataspace::STANDARD_BT2020) {
+            inputStandard = Dataspace::STANDARD_BT709;
+        }
+
         if (needsXYZConversion) {
             // The supported input color spaces are standard RGB, Display P3 and BT2020.
             switch (inputStandard) {
@@ -830,13 +835,33 @@
             // - scRGB non-linear
             // - sRGB
             // - Display P3
+            // - BT2020
             // The output data spaces could be
             // - sRGB
             // - Display P3
-            if (outputStandard == Dataspace::STANDARD_BT709) {
-                managedState.outputTransformMatrix = mDisplayP3ToSrgb;
-            } else if (outputStandard == Dataspace::STANDARD_DCI_P3) {
-                managedState.outputTransformMatrix = mSrgbToDisplayP3;
+            // - BT2020
+            switch (outputStandard) {
+                case Dataspace::STANDARD_BT2020:
+                    if (inputStandard == Dataspace::STANDARD_BT709) {
+                        managedState.outputTransformMatrix = mSrgbToBt2020;
+                    } else if (inputStandard == Dataspace::STANDARD_DCI_P3) {
+                        managedState.outputTransformMatrix = mDisplayP3ToBt2020;
+                    }
+                    break;
+                case Dataspace::STANDARD_DCI_P3:
+                    if (inputStandard == Dataspace::STANDARD_BT709) {
+                        managedState.outputTransformMatrix = mSrgbToDisplayP3;
+                    } else if (inputStandard == Dataspace::STANDARD_BT2020) {
+                        managedState.outputTransformMatrix = mBt2020ToDisplayP3;
+                    }
+                    break;
+                default:
+                    if (inputStandard == Dataspace::STANDARD_DCI_P3) {
+                        managedState.outputTransformMatrix = mDisplayP3ToSrgb;
+                    } else if (inputStandard == Dataspace::STANDARD_BT2020) {
+                        managedState.outputTransformMatrix = mBt2020ToSrgb;
+                    }
+                    break;
             }
         }
 
@@ -847,9 +872,9 @@
         if (managedState.hasColorMatrix() || managedState.hasOutputTransformMatrix() ||
             inputTransfer != outputTransfer) {
             managedState.inputTransferFunction =
-                Description::dataSpaceToTransferFunction(inputTransfer);
+                    Description::dataSpaceToTransferFunction(inputTransfer);
             managedState.outputTransferFunction =
-                Description::dataSpaceToTransferFunction(outputTransfer);
+                    Description::dataSpaceToTransferFunction(outputTransfer);
         }
 
         ProgramCache::getInstance().useProgram(managedState);
@@ -921,7 +946,7 @@
     const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK);
     const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK);
     return standard == Dataspace::STANDARD_BT2020 &&
-        (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG);
+            (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG);
 }
 
 // For convenience, we want to convert the input color space to XYZ color space first,
@@ -938,18 +963,12 @@
     const bool isInputHdrDataSpace = isHdrDataSpace(mDataSpace);
     const bool isOutputHdrDataSpace = isHdrDataSpace(mOutputDataSpace);
     const Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
-    const Dataspace outputTransfer = static_cast<Dataspace>(mOutputDataSpace &
-                                                            Dataspace::TRANSFER_MASK);
+    const Dataspace outputTransfer =
+            static_cast<Dataspace>(mOutputDataSpace & Dataspace::TRANSFER_MASK);
 
     return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer;
 }
 
-void GLES20RenderEngine::setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt) {
-    mEGLDisplay = display;
-    mEGLConfig = config;
-    mEGLContext = ctxt;
-}
-
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h b/libs/renderengine/gl/GLES20RenderEngine.h
similarity index 92%
rename from services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
rename to libs/renderengine/gl/GLES20RenderEngine.h
index b08e096..aebb319 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
+++ b/libs/renderengine/gl/GLES20RenderEngine.h
@@ -47,7 +47,8 @@
     static std::unique_ptr<GLES20RenderEngine> create(int hwcFormat, uint32_t featureFlags);
     static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
 
-    GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
+    GLES20RenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
+                       EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy);
     ~GLES20RenderEngine() override;
 
     std::unique_ptr<Framebuffer> createFramebuffer() override;
@@ -120,11 +121,12 @@
     // with PQ or HLG transfer function.
     bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
     bool needsXYZTransformMatrix() const;
-    void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt);
+    void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy);
 
     EGLDisplay mEGLDisplay;
     EGLConfig mEGLConfig;
     EGLContext mEGLContext;
+    EGLSurface mDummySurface;
     GLuint mProtectedTexName;
     GLint mMaxViewportDims[2];
     GLint mMaxTextureSize;
@@ -132,14 +134,18 @@
     GLuint mVpHeight;
     Description mState;
 
-    mat4 mSrgbToDisplayP3;
-    mat4 mDisplayP3ToSrgb;
     mat4 mSrgbToXyz;
-    mat4 mBt2020ToXyz;
     mat4 mDisplayP3ToXyz;
+    mat4 mBt2020ToXyz;
     mat4 mXyzToSrgb;
     mat4 mXyzToDisplayP3;
     mat4 mXyzToBt2020;
+    mat4 mSrgbToDisplayP3;
+    mat4 mSrgbToBt2020;
+    mat4 mDisplayP3ToSrgb;
+    mat4 mDisplayP3ToBt2020;
+    mat4 mBt2020ToSrgb;
+    mat4 mBt2020ToDisplayP3;
 
     bool mRenderToFbo = false;
     int32_t mSurfaceHeight = 0;
@@ -156,8 +162,8 @@
     const bool mUseColorManagement = false;
 };
 
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
 
 #endif /* SF_GLES20RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp b/libs/renderengine/gl/GLExtensions.cpp
similarity index 97%
rename from services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
rename to libs/renderengine/gl/GLExtensions.cpp
index 0fdb9aa..784693b 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
+++ b/libs/renderengine/gl/GLExtensions.cpp
@@ -122,6 +122,6 @@
     return mEGLExtensions.string();
 }
 
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLExtensions.h b/libs/renderengine/gl/GLExtensions.h
similarity index 96%
rename from services/surfaceflinger/RenderEngine/gl/GLExtensions.h
rename to libs/renderengine/gl/GLExtensions.h
index 02ad965..382c23a 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLExtensions.h
+++ b/libs/renderengine/gl/GLExtensions.h
@@ -75,8 +75,8 @@
     char const* getEGLExtensions() const;
 };
 
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
 
 #endif // ANDROID_SF_GLEXTENSION_H
diff --git a/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
similarity index 88%
rename from services/surfaceflinger/RenderEngine/gl/GLFramebuffer.cpp
rename to libs/renderengine/gl/GLFramebuffer.cpp
index 83d2bde..2bd4e7f 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -28,8 +28,7 @@
 namespace gl {
 
 GLFramebuffer::GLFramebuffer(const GLES20RenderEngine& engine)
-        : mEGLDisplay(engine.getEGLDisplay()),
-          mEGLImage(EGL_NO_IMAGE_KHR) {
+      : mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) {
     glGenTextures(1, &mTextureName);
     glGenFramebuffers(1, &mFramebufferName);
 }
@@ -49,8 +48,7 @@
     }
 
     if (nativeBuffer) {
-        mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
-                                      EGL_NATIVE_BUFFER_ANDROID,
+        mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
                                       nativeBuffer, nullptr);
         if (mEGLImage == EGL_NO_IMAGE_KHR) {
             return false;
@@ -61,6 +59,6 @@
     return true;
 }
 
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
similarity index 95%
rename from services/surfaceflinger/RenderEngine/gl/GLFramebuffer.h
rename to libs/renderengine/gl/GLFramebuffer.h
index 193cbdc..90c6f4a 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLFramebuffer.h
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -51,6 +51,6 @@
     int32_t mBufferWidth = 0;
 };
 
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp
similarity index 96%
rename from services/surfaceflinger/RenderEngine/gl/GLImage.cpp
rename to libs/renderengine/gl/GLImage.cpp
index 746f3e7..5a92093 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLImage.cpp
+++ b/libs/renderengine/gl/GLImage.cpp
@@ -19,8 +19,8 @@
 #include <vector>
 
 #include <log/log.h>
-#include "GLExtensions.h"
 #include "GLES20RenderEngine.h"
+#include "GLExtensions.h"
 
 namespace android {
 namespace renderengine {
@@ -70,6 +70,6 @@
     return true;
 }
 
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLImage.h b/libs/renderengine/gl/GLImage.h
similarity index 94%
rename from services/surfaceflinger/RenderEngine/gl/GLImage.h
rename to libs/renderengine/gl/GLImage.h
index f670783..0e451f8 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLImage.h
+++ b/libs/renderengine/gl/GLImage.h
@@ -47,6 +47,6 @@
     DISALLOW_COPY_AND_ASSIGN(GLImage);
 };
 
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLSurface.cpp b/libs/renderengine/gl/GLSurface.cpp
similarity index 91%
rename from services/surfaceflinger/RenderEngine/gl/GLSurface.cpp
rename to libs/renderengine/gl/GLSurface.cpp
index 104af56..2d694e9 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLSurface.cpp
+++ b/libs/renderengine/gl/GLSurface.cpp
@@ -29,8 +29,8 @@
       : mEGLDisplay(engine.getEGLDisplay()), mEGLConfig(engine.getEGLConfig()) {
     // RE does not assume any config when EGL_KHR_no_config_context is supported
     if (mEGLConfig == EGL_NO_CONFIG_KHR) {
-        mEGLConfig = GLES20RenderEngine::chooseEglConfig(mEGLDisplay,
-                                                         PIXEL_FORMAT_RGBA_8888, false);
+        mEGLConfig =
+                GLES20RenderEngine::chooseEglConfig(mEGLDisplay, PIXEL_FORMAT_RGBA_8888, false);
     }
 }
 
@@ -100,6 +100,6 @@
     return mSurfaceHeight;
 }
 
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLSurface.h b/libs/renderengine/gl/GLSurface.h
similarity index 96%
rename from services/surfaceflinger/RenderEngine/gl/GLSurface.h
rename to libs/renderengine/gl/GLSurface.h
index 8aa223a..092d371 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLSurface.h
+++ b/libs/renderengine/gl/GLSurface.h
@@ -71,6 +71,6 @@
     DISALLOW_COPY_AND_ASSIGN(GLSurface);
 };
 
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/Program.cpp b/libs/renderengine/gl/Program.cpp
similarity index 96%
rename from services/surfaceflinger/RenderEngine/gl/Program.cpp
rename to libs/renderengine/gl/Program.cpp
index 7ae5736..7d2ea90 100644
--- a/services/surfaceflinger/RenderEngine/gl/Program.cpp
+++ b/libs/renderengine/gl/Program.cpp
@@ -130,16 +130,15 @@
         // The output transform matrix and color matrix can be combined as one matrix
         // that is applied right before applying OETF.
         mat4 outputTransformMatrix = desc.colorMatrix * desc.outputTransformMatrix;
-        glUniformMatrix4fv(mOutputTransformMatrixLoc, 1, GL_FALSE,
-                           outputTransformMatrix.asArray());
+        glUniformMatrix4fv(mOutputTransformMatrixLoc, 1, GL_FALSE, outputTransformMatrix.asArray());
     }
     if (mDisplayMaxLuminanceLoc >= 0) {
-        glUniform1f(mDisplayMaxLuminanceLoc, desc.displayMaxLuminance) ;
+        glUniform1f(mDisplayMaxLuminanceLoc, desc.displayMaxLuminance);
     }
     // these uniforms are always present
     glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.projectionMatrix.asArray());
 }
 
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/Program.h b/libs/renderengine/gl/Program.h
similarity index 96%
rename from services/surfaceflinger/RenderEngine/gl/Program.h
rename to libs/renderengine/gl/Program.h
index b1ce8cf..99bf0f0 100644
--- a/services/surfaceflinger/RenderEngine/gl/Program.h
+++ b/libs/renderengine/gl/Program.h
@@ -87,8 +87,8 @@
     GLint mOutputTransformMatrixLoc;
 };
 
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
 
 #endif /* SF_RENDER_ENGINE_PROGRAM_H */
diff --git a/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
similarity index 97%
rename from services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
rename to libs/renderengine/gl/ProgramCache.cpp
index 6d431b6..464fc15 100644
--- a/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -130,18 +130,18 @@
                               : description.texture.getTextureTarget() == GL_TEXTURE_2D
                                       ? Key::TEXTURE_2D
                                       : Key::TEXTURE_OFF)
-            .set(Key::ALPHA_MASK,
-                 (description.color.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE)
+            .set(Key::ALPHA_MASK, (description.color.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE)
             .set(Key::BLEND_MASK,
                  description.isPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
             .set(Key::OPACITY_MASK,
                  description.isOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
             .set(Key::Key::INPUT_TRANSFORM_MATRIX_MASK,
-                 description.hasInputTransformMatrix() ?
-                     Key::INPUT_TRANSFORM_MATRIX_ON : Key::INPUT_TRANSFORM_MATRIX_OFF)
+                 description.hasInputTransformMatrix() ? Key::INPUT_TRANSFORM_MATRIX_ON
+                                                       : Key::INPUT_TRANSFORM_MATRIX_OFF)
             .set(Key::Key::OUTPUT_TRANSFORM_MATRIX_MASK,
-                 description.hasOutputTransformMatrix() || description.hasColorMatrix() ?
-                     Key::OUTPUT_TRANSFORM_MATRIX_ON : Key::OUTPUT_TRANSFORM_MATRIX_OFF);
+                 description.hasOutputTransformMatrix() || description.hasColorMatrix()
+                         ? Key::OUTPUT_TRANSFORM_MATRIX_ON
+                         : Key::OUTPUT_TRANSFORM_MATRIX_OFF);
 
     needs.set(Key::Y410_BT2020_MASK,
               description.isY410BT2020 ? Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF);
@@ -631,7 +631,8 @@
             // avoid divide by 0 by adding 0.5/256 to the alpha channel
             fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
         }
-        fs << "gl_FragColor.rgb = OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))));";
+        fs << "gl_FragColor.rgb = "
+              "OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))));";
         if (!needs.isOpaque() && needs.isPremultiplied()) {
             // and re-premultiply if needed after gamma correction
             fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
@@ -678,6 +679,6 @@
     }
 }
 
-}  // namespace gl
-}  // namespace renderengine
-}  // namespace android
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
similarity index 95%
rename from services/surfaceflinger/RenderEngine/gl/ProgramCache.h
rename to libs/renderengine/gl/ProgramCache.h
index 120b3d1..d60fee6 100644
--- a/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -159,14 +159,10 @@
 
         // for use by std::unordered_map
 
-        bool operator==(const Key& other) const {
-            return mKey == other.mKey;
-        }
+        bool operator==(const Key& other) const { return mKey == other.mKey; }
 
         struct Hash {
-            size_t operator()(const Key& key) const {
-                return static_cast<size_t>(key.mKey);
-            }
+            size_t operator()(const Key& key) const { return static_cast<size_t>(key.mKey); }
         };
     };
 
@@ -205,11 +201,11 @@
     std::unordered_map<Key, std::unique_ptr<Program>, Key::Hash> mCache;
 };
 
-}  // namespace gl
-}  // namespace renderengine
+} // namespace gl
+} // namespace renderengine
 
 ANDROID_BASIC_TYPES_TRAITS(renderengine::gl::ProgramCache::Key)
 
-}  // namespace android
+} // namespace android
 
 #endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
similarity index 100%
rename from services/surfaceflinger/RenderEngine/include/renderengine/DisplaySettings.h
rename to libs/renderengine/include/renderengine/DisplaySettings.h
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h b/libs/renderengine/include/renderengine/Framebuffer.h
similarity index 93%
rename from services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h
rename to libs/renderengine/include/renderengine/Framebuffer.h
index 6595466..558b9c7 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h
+++ b/libs/renderengine/include/renderengine/Framebuffer.h
@@ -30,5 +30,5 @@
     virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) = 0;
 };
 
-}   // namespace renderengine
-}   // namespace android
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Image.h b/libs/renderengine/include/renderengine/Image.h
similarity index 93%
rename from services/surfaceflinger/RenderEngine/include/renderengine/Image.h
rename to libs/renderengine/include/renderengine/Image.h
index 85ec91a..3bb4731 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Image.h
+++ b/libs/renderengine/include/renderengine/Image.h
@@ -27,6 +27,5 @@
     virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) = 0;
 };
 
-}  // namespace renderengine
-}  // namespace android
-
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
similarity index 100%
rename from services/surfaceflinger/RenderEngine/include/renderengine/LayerSettings.h
rename to libs/renderengine/include/renderengine/LayerSettings.h
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h b/libs/renderengine/include/renderengine/Mesh.h
similarity index 97%
rename from services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
rename to libs/renderengine/include/renderengine/Mesh.h
index 15d2a11..fe9022d 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
+++ b/libs/renderengine/include/renderengine/Mesh.h
@@ -101,6 +101,6 @@
     Primitive mPrimitive;
 };
 
-}  // namespace renderengine
-}  // namespace android
+} // namespace renderengine
+} // namespace android
 #endif /* SF_RENDER_ENGINE_MESH_H */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
similarity index 93%
rename from services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
rename to libs/renderengine/include/renderengine/RenderEngine.h
index f5d3d6b..becb3c3 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -58,7 +58,7 @@
 class RenderEngine {
 public:
     enum FeatureFlag {
-        USE_COLOR_MANAGEMENT = 1 << 0, // Device manages color
+        USE_COLOR_MANAGEMENT = 1 << 0,      // Device manages color
         USE_HIGH_PRIORITY_CONTEXT = 1 << 1, // Use high priority context
     };
 
@@ -100,8 +100,8 @@
     virtual bool waitFence(base::unique_fd fenceFd) = 0;
 
     virtual void clearWithColor(float red, float green, float blue, float alpha) = 0;
-    virtual void fillRegionWithColor(const Region& region, float red, float green,
-                                     float blue, float alpha) = 0;
+    virtual void fillRegionWithColor(const Region& region, float red, float green, float blue,
+                                     float alpha) = 0;
 
     virtual void setScissor(const Rect& region) = 0;
     virtual void disableScissor() = 0;
@@ -176,11 +176,10 @@
 class BindNativeBufferAsFramebuffer {
 public:
     BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer)
-          : mEngine(engine),
-            mFramebuffer(mEngine.createFramebuffer()),
-            mStatus(NO_ERROR) {
-        mStatus = mFramebuffer->setNativeWindowBuffer(buffer) ?
-                  mEngine.bindFrameBuffer(mFramebuffer.get()) : NO_MEMORY;
+          : mEngine(engine), mFramebuffer(mEngine.createFramebuffer()), mStatus(NO_ERROR) {
+        mStatus = mFramebuffer->setNativeWindowBuffer(buffer)
+                ? mEngine.bindFrameBuffer(mFramebuffer.get())
+                : NO_MEMORY;
     }
     ~BindNativeBufferAsFramebuffer() {
         mFramebuffer->setNativeWindowBuffer(nullptr);
@@ -209,8 +208,8 @@
     const uint32_t mFeatureFlags;
 };
 
-}  // namespace impl
-}  // namespace renderengine
-}  // namespace android
+} // namespace impl
+} // namespace renderengine
+} // namespace android
 
 #endif /* SF_RENDERENGINE_H_ */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Surface.h b/libs/renderengine/include/renderengine/Surface.h
similarity index 95%
rename from services/surfaceflinger/RenderEngine/include/renderengine/Surface.h
rename to libs/renderengine/include/renderengine/Surface.h
index 3999ddc..ba7331d 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Surface.h
+++ b/libs/renderengine/include/renderengine/Surface.h
@@ -42,5 +42,5 @@
     virtual int32_t getHeight() const = 0;
 };
 
-}  // namespace renderengine
-}  // namespace android
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Texture.h b/libs/renderengine/include/renderengine/Texture.h
similarity index 96%
rename from services/surfaceflinger/RenderEngine/include/renderengine/Texture.h
rename to libs/renderengine/include/renderengine/Texture.h
index fb3e0cc..c69ace0 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Texture.h
+++ b/libs/renderengine/include/renderengine/Texture.h
@@ -55,6 +55,6 @@
     mat4 mTextureMatrix;
 };
 
-}  // namespace renderengine
-}  // namespace android
+} // namespace renderengine
+} // namespace android
 #endif /* SF_RENDER_ENGINE_TEXTURE_H */
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h b/libs/renderengine/include/renderengine/private/Description.h
similarity index 95%
rename from services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
rename to libs/renderengine/include/renderengine/private/Description.h
index 911bb7a..eadd656 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/private/Description.h
+++ b/libs/renderengine/include/renderengine/private/Description.h
@@ -17,8 +17,8 @@
 #ifndef SF_RENDER_ENGINE_DESCRIPTION_H_
 #define SF_RENDER_ENGINE_DESCRIPTION_H_
 
-#include <ui/GraphicTypes.h>
 #include <renderengine/Texture.h>
+#include <ui/GraphicTypes.h>
 
 namespace android {
 namespace renderengine {
@@ -33,7 +33,7 @@
         LINEAR,
         SRGB,
         ST2084,
-        HLG,  // Hybrid Log-Gamma for HDR.
+        HLG, // Hybrid Log-Gamma for HDR.
     };
 
     static TransferFunction dataSpaceToTransferFunction(ui::Dataspace dataSpace);
@@ -75,7 +75,7 @@
     mat4 outputTransformMatrix;
 };
 
-}  // namespace renderengine
-}  // namespace android
+} // namespace renderengine
+} // namespace android
 
 #endif /* SF_RENDER_ENGINE_DESCRIPTION_H_ */
diff --git a/services/surfaceflinger/RenderEngine/tests/Android.bp b/libs/renderengine/tests/Android.bp
similarity index 100%
rename from services/surfaceflinger/RenderEngine/tests/Android.bp
rename to libs/renderengine/tests/Android.bp
diff --git a/services/surfaceflinger/RenderEngine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
similarity index 100%
rename from services/surfaceflinger/RenderEngine/tests/RenderEngineTest.cpp
rename to libs/renderengine/tests/RenderEngineTest.cpp
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 44a947e..8cc1a4e 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -37,7 +37,6 @@
 #pragma clang diagnostic pop
 
 #include <ui/BufferHubBuffer.h>
-#include <ui/DetachedBufferHandle.h>
 
 #include <poll.h>
 
@@ -159,7 +158,7 @@
 
     // If all imports succeed, replace the previous buffer and id.
     mId = bufferId;
-    mBufferStateBit = bufferTraits.buffer_state_bit();
+    mClientStateMask = bufferTraits.client_state_mask();
 
     // TODO(b/112012161) Set up shared fences.
     ALOGD("BufferHubBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64 ".", id(),
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index c50d1d0..5a1ddee 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -22,7 +22,6 @@
 
 #include <grallocusage/GrallocUsageConversion.h>
 
-#include <ui/DetachedBufferHandle.h>
 #include <ui/Gralloc2.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
@@ -490,24 +489,6 @@
     return NO_ERROR;
 }
 
-bool GraphicBuffer::isDetachedBuffer() const {
-    return mDetachedBufferHandle && mDetachedBufferHandle->isValid();
-}
-
-status_t GraphicBuffer::setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> channel) {
-    if (isDetachedBuffer()) {
-        ALOGW("setDetachedBuffer: there is already a BufferHub channel associated with this "
-              "GraphicBuffer. Replacing the old one.");
-    }
-
-    mDetachedBufferHandle = std::move(channel);
-    return NO_ERROR;
-}
-
-std::unique_ptr<DetachedBufferHandle> GraphicBuffer::takeDetachedBufferHandle() {
-    return std::move(mDetachedBufferHandle);
-}
-
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index cefe5b3..daf6192 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -88,7 +88,7 @@
 
     // A state mask which is unique to a buffer hub client among all its siblings sharing the same
     // concrete graphic buffer.
-    uint64_t buffer_state_bit() const { return mBufferStateBit; }
+    uint64_t client_state_mask() const { return mClientStateMask; }
 
     size_t user_metadata_size() const { return mMetadata.user_metadata_size(); }
 
@@ -126,7 +126,7 @@
 
     // Global id for the buffer that is consistent across processes.
     int mId = -1;
-    uint64_t mBufferStateBit = 0;
+    uint64_t mClientStateMask = 0;
 
     // Wrapps the gralloc buffer handle of this buffer.
     dvr::NativeHandleWrapper<pdx::LocalHandle> mBufferHandle;
diff --git a/libs/ui/include/ui/DetachedBufferHandle.h b/libs/ui/include/ui/DetachedBufferHandle.h
deleted file mode 100644
index f3c328d..0000000
--- a/libs/ui/include/ui/DetachedBufferHandle.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
-#define ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
-
-#include <pdx/channel_handle.h>
-
-#include <memory>
-
-namespace android {
-
-// A wrapper that holds a pdx::LocalChannelHandle object. From the handle, a BufferHub buffer can be
-// created. Current implementation assumes that the underlying transport is using libpdx (thus
-// holding a pdx::LocalChannelHandle object), but future implementation can change it to a Binder
-// backend if ever needed.
-class DetachedBufferHandle {
-public:
-    static std::unique_ptr<DetachedBufferHandle> Create(pdx::LocalChannelHandle handle) {
-        return std::unique_ptr<DetachedBufferHandle>(new DetachedBufferHandle(std::move(handle)));
-    }
-
-    // Accessors to get or take the internal pdx::LocalChannelHandle.
-    pdx::LocalChannelHandle& handle() { return mHandle; }
-    const pdx::LocalChannelHandle& handle() const { return mHandle; }
-
-    // Returns whether the DetachedBufferHandle holds a BufferHub channel.
-    bool isValid() const { return mHandle.valid(); }
-
-private:
-    // Constructs a DetachedBufferHandle from a pdx::LocalChannelHandle.
-    explicit DetachedBufferHandle(pdx::LocalChannelHandle handle) : mHandle(std::move(handle)) {}
-
-    pdx::LocalChannelHandle mHandle;
-};
-
-} // namespace android
-
-#endif // ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index cc38982..e794462 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -34,7 +34,6 @@
 
 namespace android {
 
-class DetachedBufferHandle;
 class GraphicBufferMapper;
 
 // ===========================================================================
@@ -191,11 +190,6 @@
     status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
     status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
 
-    // Sets and takes DetachedBuffer. Should only be called from BufferHub.
-    bool isDetachedBuffer() const;
-    status_t setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> detachedBuffer);
-    std::unique_ptr<DetachedBufferHandle> takeDetachedBufferHandle();
-
 private:
     ~GraphicBuffer();
 
@@ -246,17 +240,6 @@
     // match the BufferQueue's internal generation number (set through
     // IGBP::setGenerationNumber), attempts to attach the buffer will fail.
     uint32_t mGenerationNumber;
-
-    // Stores a BufferHub handle that can be used to re-attach this GraphicBuffer back into a
-    // BufferHub producer/consumer set. In terms of GraphicBuffer's relationship with BufferHub,
-    // there are three different modes:
-    // 1. Legacy mode: GraphicBuffer is not backed by BufferHub and mDetachedBufferHandle must be
-    //    invalid.
-    // 2. Detached mode: GraphicBuffer is backed by BufferHub, but not part of a producer/consumer
-    //    set. In this mode, mDetachedBufferHandle must be valid.
-    // 3. Attached mode: GraphicBuffer is backed by BufferHub and it's part of a producer/consumer
-    //    set. In this mode, mDetachedBufferHandle must be invalid.
-    std::unique_ptr<DetachedBufferHandle> mDetachedBufferHandle;
 };
 
 }; // namespace android
diff --git a/libs/ui/include_vndk/ui/Transform.h b/libs/ui/include_vndk/ui/Transform.h
new file mode 120000
index 0000000..60633c2
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Transform.h
@@ -0,0 +1 @@
+../../include/ui/Transform.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 228d202..1521e1d 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -29,16 +29,19 @@
 }
 
 cc_test {
-    name: "GraphicBuffer_test",
-    shared_libs: ["libpdx_default_transport", "libui", "libutils"],
-    srcs: ["GraphicBuffer_test.cpp"],
-    cflags: ["-Wall", "-Werror"],
-}
-
-cc_test {
     name: "BufferHubBuffer_test",
-    header_libs: ["libbufferhub_headers", "libdvr_headers"],
-    shared_libs: ["libpdx_default_transport", "libui", "libutils"],
+    header_libs: [
+        "libbufferhub_headers",
+        "libdvr_headers"
+    ],
+    shared_libs: [
+        "android.frameworks.bufferhub@1.0",
+        "libhidlbase",
+        "libhwbinder",
+        "libpdx_default_transport",
+        "libui",
+        "libutils"
+    ],
     srcs: ["BufferHubBuffer_test.cpp"],
     cflags: ["-Wall", "-Werror"],
 }
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index be06ad2..606aee60 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,7 +16,11 @@
 
 #define LOG_TAG "BufferHubBufferTest"
 
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
 #include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/IPCThreadState.h>
 #include <ui/BufferHubBuffer.h>
 
 namespace android {
@@ -30,15 +34,20 @@
 const int kUsage = 0;
 const size_t kUserMetadataSize = 0;
 
-} // namespace
-
-using BufferHubBufferTest = ::testing::Test;
-
 using dvr::BufferHubDefs::IsBufferGained;
+using dvr::BufferHubDefs::kFirstClientBitMask;
 using dvr::BufferHubDefs::kMetadataHeaderSize;
-using dvr::BufferHubDefs::kProducerStateBit;
+using frameworks::bufferhub::V1_0::BufferHubStatus;
+using frameworks::bufferhub::V1_0::IBufferClient;
+using frameworks::bufferhub::V1_0::IBufferHub;
+using hardware::hidl_handle;
+using hidl::base::V1_0::IBase;
 using pdx::LocalChannelHandle;
 
+class BufferHubBufferTest : public ::testing::Test {
+    void SetUp() override { android::hardware::ProcessState::self()->startThreadPool(); }
+};
+
 TEST_F(BufferHubBufferTest, CreateBufferHubBufferFails) {
     // Buffer Creation will fail: BLOB format requires height to be 1.
     auto b1 = BufferHubBuffer::Create(kWidth, /*height=*/2, kLayerCount,
@@ -75,6 +84,8 @@
     auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
                                       kUserMetadataSize);
     int id1 = b1->id();
+    uint64_t bufferStateMask1 = b1->client_state_mask();
+    EXPECT_NE(bufferStateMask1, 0ULL);
     EXPECT_TRUE(b1->IsValid());
     EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
 
@@ -96,16 +107,14 @@
     EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
 
     int id2 = b2->id();
+    uint64_t bufferStateMask2 = b2->client_state_mask();
+    EXPECT_NE(bufferStateMask2, 0ULL);
 
     // These two buffer instances are based on the same physical buffer under the
     // hood, so they should share the same id.
     EXPECT_EQ(id1, id2);
-    // We use buffer_state_bit() to tell those two instances apart.
-    EXPECT_NE(b1->buffer_state_bit(), b2->buffer_state_bit());
-    EXPECT_NE(b1->buffer_state_bit(), 0ULL);
-    EXPECT_NE(b2->buffer_state_bit(), 0ULL);
-    EXPECT_NE(b1->buffer_state_bit(), kProducerStateBit);
-    EXPECT_NE(b2->buffer_state_bit(), kProducerStateBit);
+    // We use client_state_mask() to tell those two instances apart.
+    EXPECT_NE(bufferStateMask1, bufferStateMask2);
 
     // Both buffer instances should be in gained state.
     EXPECT_TRUE(IsBufferGained(b1->buffer_state()));
@@ -115,4 +124,20 @@
     return;
 }
 
+TEST_F(BufferHubBufferTest, ConnectHidlServer) {
+    sp<IBufferHub> bufferhub = IBufferHub::getService();
+    ASSERT_NE(nullptr, bufferhub.get());
+
+    // TODO(b/116681016): Fill in real test once the interface gets implemented..
+    hidl_handle handle;
+    EXPECT_TRUE(bufferhub
+                        ->importBuffer(handle,
+                                       [](const auto& client, const auto& ret) {
+                                           EXPECT_EQ(client, nullptr);
+                                           EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
+                                       })
+                        .isOk());
+}
+
+} // namespace
 } // namespace android
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
deleted file mode 100644
index eb679ac..0000000
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GraphicBufferTest"
-
-#include <ui/DetachedBufferHandle.h>
-#include <ui/GraphicBuffer.h>
-
-#include <gtest/gtest.h>
-
-namespace android {
-
-namespace {
-
-constexpr uint32_t kTestWidth = 1024;
-constexpr uint32_t kTestHeight = 1;
-constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB;
-constexpr uint32_t kTestLayerCount = 1;
-constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN;
-
-} // namespace
-
-class GraphicBufferTest : public testing::Test {};
-
-TEST_F(GraphicBufferTest, DetachedBuffer) {
-    sp<GraphicBuffer> buffer(
-            new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, kTestUsage));
-
-    // Currently a newly allocated GraphicBuffer is in legacy mode, i.e. not associated with
-    // BufferHub. But this may change in the future.
-    EXPECT_FALSE(buffer->isDetachedBuffer());
-
-    pdx::LocalChannelHandle channel{nullptr, 1234};
-    EXPECT_TRUE(channel.valid());
-
-    std::unique_ptr<DetachedBufferHandle> handle = DetachedBufferHandle::Create(std::move(channel));
-    EXPECT_FALSE(channel.valid());
-    EXPECT_TRUE(handle->isValid());
-    EXPECT_TRUE(handle->handle().valid());
-
-    buffer->setDetachedBufferHandle(std::move(handle));
-    EXPECT_TRUE(handle == nullptr);
-    EXPECT_TRUE(buffer->isDetachedBuffer());
-
-    handle = buffer->takeDetachedBufferHandle();
-    EXPECT_TRUE(handle != nullptr);
-    EXPECT_TRUE(handle->isValid());
-    EXPECT_FALSE(buffer->isDetachedBuffer());
-}
-
-} // namespace android
diff --git a/libs/vr/CleanSpec.mk b/libs/vr/CleanSpec.mk
deleted file mode 100644
index a17c9b2..0000000
--- a/libs/vr/CleanSpec.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2012 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.
-#
-
-# If you don't need to do a full clean build but would like to touch
-# a file or delete some intermediate files, add a clean step to the end
-# of the list.  These steps will only be run once, if they haven't been
-# run before.
-#
-# E.g.:
-#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
-#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
-#
-# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
-# files that are missing or have been moved.
-#
-# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
-# Use $(OUT_DIR) to refer to the "out" directory.
-#
-# If you need to re-do something that's already mentioned, just copy
-# the command and add it to the bottom of the list.  E.g., if a change
-# that you made last week required touching a file and a change you
-# made today requires touching the same file, just copy the old
-# touch step and add it to the end of the list.
-#
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
-
-# For example:
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
-#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
-#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
-$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libdvr.so" -print0 | xargs -0 rm -f)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
diff --git a/libs/vr/libbufferhub/buffer_client_impl.cpp b/libs/vr/libbufferhub/buffer_client_impl.cpp
index 6bef98a..30cbb9f 100644
--- a/libs/vr/libbufferhub/buffer_client_impl.cpp
+++ b/libs/vr/libbufferhub/buffer_client_impl.cpp
@@ -10,6 +10,8 @@
       : BpInterface<IBufferClient>(impl) {}
 
   bool isValid() override;
+
+  status_t duplicate(uint64_t* outToken) override;
 };
 
 IMPLEMENT_META_INTERFACE(BufferClient, "android.dvr.IBufferClient");
@@ -17,6 +19,7 @@
 // Transaction code
 enum {
   IS_VALID = IBinder::FIRST_CALL_TRANSACTION,
+  DUPLICATE,
 };
 
 bool BpBufferClient::isValid() {
@@ -38,13 +41,42 @@
   }
 }
 
+status_t BpBufferClient::duplicate(uint64_t* outToken) {
+  Parcel data, reply;
+  status_t ret =
+      data.writeInterfaceToken(IBufferClient::getInterfaceDescriptor());
+  if (ret != NO_ERROR) {
+    ALOGE("BpBufferClient::duplicate: failed to write into parcel; errno=%d",
+          ret);
+    return ret;
+  }
+
+  ret = remote()->transact(DUPLICATE, data, &reply);
+  if (ret == NO_ERROR) {
+    *outToken = reply.readUint64();
+    return NO_ERROR;
+  } else {
+    ALOGE("BpBufferClient::duplicate: failed to transact; errno=%d", ret);
+    return ret;
+  }
+}
+
 status_t BnBufferClient::onTransact(uint32_t code, const Parcel& data,
                                     Parcel* reply, uint32_t flags) {
   switch (code) {
     case IS_VALID: {
       CHECK_INTERFACE(IBufferClient, data, reply);
       return reply->writeBool(isValid());
-    } break;
+    }
+    case DUPLICATE: {
+      CHECK_INTERFACE(IBufferClient, data, reply);
+      uint64_t token = 0;
+      status_t ret = duplicate(&token);
+      if (ret != NO_ERROR) {
+        return ret;
+      }
+      return reply->writeUint64(token);
+    }
     default:
       // Should not reach except binder defined transactions such as dumpsys
       return BBinder::onTransact(code, data, reply, flags);
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 8c6e7e2..73ca69b 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -5,7 +5,6 @@
 #include <sys/epoll.h>
 #include <sys/eventfd.h>
 #include <ui/BufferHubBuffer.h>
-#include <ui/DetachedBufferHandle.h>
 
 #include <mutex>
 #include <thread>
@@ -29,8 +28,8 @@
 using android::dvr::BufferHubDefs::IsBufferPosted;
 using android::dvr::BufferHubDefs::IsBufferReleased;
 using android::dvr::BufferHubDefs::kConsumerStateMask;
+using android::dvr::BufferHubDefs::kFirstClientBitMask;
 using android::dvr::BufferHubDefs::kMetadataHeaderSize;
-using android::dvr::BufferHubDefs::kProducerStateBit;
 using android::pdx::LocalChannelHandle;
 using android::pdx::LocalHandle;
 using android::pdx::Status;
@@ -41,7 +40,10 @@
 const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
 const int kUsage = 0;
 const size_t kUserMetadataSize = 0;
-const size_t kMaxConsumerCount = 63;
+// Maximum number of consumers for the buffer that only has one producer in the
+// test.
+const size_t kMaxConsumerCount =
+    android::dvr::BufferHubDefs::kMaxNumberOfClients - 1;
 const int kPollTimeoutMs = 100;
 
 using LibBufferHubTest = ::testing::Test;
@@ -59,19 +61,19 @@
   ASSERT_TRUE(c2.get() != nullptr);
 
   // Producer state mask is unique, i.e. 1.
-  EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit);
+  EXPECT_EQ(p->client_state_mask(), kFirstClientBitMask);
   // Consumer state mask cannot have producer bit on.
-  EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0U);
+  EXPECT_EQ(c->client_state_mask() & kFirstClientBitMask, 0U);
   // Consumer state mask must be a single, i.e. power of 2.
-  EXPECT_NE(c->buffer_state_bit(), 0U);
-  EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0U);
+  EXPECT_NE(c->client_state_mask(), 0U);
+  EXPECT_EQ(c->client_state_mask() & (c->client_state_mask() - 1), 0U);
   // Consumer state mask cannot have producer bit on.
-  EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0U);
+  EXPECT_EQ(c2->client_state_mask() & kFirstClientBitMask, 0U);
   // Consumer state mask must be a single, i.e. power of 2.
-  EXPECT_NE(c2->buffer_state_bit(), 0U);
-  EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0U);
+  EXPECT_NE(c2->client_state_mask(), 0U);
+  EXPECT_EQ(c2->client_state_mask() & (c2->client_state_mask() - 1), 0U);
   // Each consumer should have unique bit.
-  EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0U);
+  EXPECT_EQ(c->client_state_mask() & c2->client_state_mask(), 0U);
 
   // Initial state: producer not available, consumers not available.
   EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
@@ -178,16 +180,16 @@
   ASSERT_TRUE(p.get() != nullptr);
 
   // It's ok to create up to kMaxConsumerCount consumer buffers.
-  uint64_t buffer_state_bits = p->buffer_state_bit();
+  uint64_t client_state_masks = p->client_state_mask();
   std::array<std::unique_ptr<ConsumerBuffer>, kMaxConsumerCount> cs;
   for (size_t i = 0; i < kMaxConsumerCount; i++) {
     cs[i] = ConsumerBuffer::Import(p->CreateConsumer());
     ASSERT_TRUE(cs[i].get() != nullptr);
     // Expect all buffers have unique state mask.
-    EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U);
-    buffer_state_bits |= cs[i]->buffer_state_bit();
+    EXPECT_EQ(client_state_masks & cs[i]->client_state_mask(), 0U);
+    client_state_masks |= cs[i]->client_state_mask();
   }
-  EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
+  EXPECT_EQ(client_state_masks, kFirstClientBitMask | kConsumerStateMask);
 
   // The 64th creation will fail with out-of-memory error.
   auto state = p->CreateConsumer();
@@ -195,14 +197,14 @@
 
   // Release any consumer should allow us to re-create.
   for (size_t i = 0; i < kMaxConsumerCount; i++) {
-    buffer_state_bits &= ~cs[i]->buffer_state_bit();
+    client_state_masks &= ~cs[i]->client_state_mask();
     cs[i] = nullptr;
     cs[i] = ConsumerBuffer::Import(p->CreateConsumer());
     ASSERT_TRUE(cs[i].get() != nullptr);
     // The released state mask will be reused.
-    EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U);
-    buffer_state_bits |= cs[i]->buffer_state_bit();
-    EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
+    EXPECT_EQ(client_state_masks & cs[i]->client_state_mask(), 0U);
+    client_state_masks |= cs[i]->client_state_mask();
+    EXPECT_EQ(client_state_masks, kFirstClientBitMask | kConsumerStateMask);
   }
 }
 
@@ -214,13 +216,12 @@
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c.get() != nullptr);
 
-  uint64_t context;
   LocalHandle fence;
 
   // The producer buffer starts in gained state.
 
   // Acquire, release, and gain in gained state should fail.
-  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence));
   EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
   EXPECT_EQ(-EALREADY, p->Gain(&fence));
 
@@ -233,10 +234,10 @@
   EXPECT_EQ(-EBUSY, p->Gain(&fence));
 
   // Acquire in posted state should succeed.
-  EXPECT_LE(0, c->Acquire(&fence, &context));
+  EXPECT_LE(0, c->Acquire(&fence));
 
   // Acquire, post, and gain in acquired state should fail.
-  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence));
   EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
   EXPECT_EQ(-EBUSY, p->Gain(&fence));
 
@@ -246,14 +247,14 @@
 
   // Release, acquire, and post in released state should fail.
   EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
-  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence));
   EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
 
   // Gain in released state should succeed.
   EXPECT_EQ(0, p->Gain(&fence));
 
   // Acquire, release, and gain in gained state should fail.
-  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence));
   EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
   EXPECT_EQ(-EALREADY, p->Gain(&fence));
 }
@@ -329,6 +330,36 @@
   EXPECT_FALSE(invalid_fence.IsValid());
 }
 
+TEST_F(LibBufferHubTest, TestGainPostedBuffer) {
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+
+  // The producer buffer starts in gained state. Post the buffer.
+  ASSERT_EQ(0, p->Post(LocalHandle()));
+
+  // Gain in posted state should only succeed with gain_posted_buffer = true.
+  LocalHandle invalid_fence;
+  EXPECT_EQ(-EBUSY, p->Gain(&invalid_fence, false));
+  EXPECT_EQ(0, p->Gain(&invalid_fence, true));
+}
+
+TEST_F(LibBufferHubTest, TestGainPostedBufferAsync) {
+  std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+
+  // The producer buffer starts in gained state. Post the buffer.
+  ASSERT_EQ(0, p->Post(LocalHandle()));
+
+  // GainAsync in posted state should only succeed with gain_posted_buffer
+  // equals true.
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+  EXPECT_EQ(-EBUSY, p->GainAsync(&metadata, &invalid_fence, false));
+  EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence, true));
+}
+
 TEST_F(LibBufferHubTest, TestZeroConsumer) {
   std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
       kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
@@ -373,7 +404,7 @@
   EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
   for (size_t i = 0; i < kMaxConsumerCount; i++) {
     EXPECT_TRUE(
-        IsBufferPosted(cs[i]->buffer_state(), cs[i]->buffer_state_bit()));
+        IsBufferPosted(cs[i]->buffer_state(), cs[i]->client_state_mask()));
     EXPECT_LT(0, RETRY_EINTR(cs[i]->Poll(kPollTimeoutMs)));
     EXPECT_EQ(0, cs[i]->AcquireAsync(&metadata, &invalid_fence));
     EXPECT_TRUE(IsBufferAcquired(p->buffer_state()));
@@ -491,7 +522,7 @@
   EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
   LocalHandle fence;
   Metadata m2 = {};
-  EXPECT_EQ(0, c->Acquire(&fence, &m2));
+  EXPECT_EQ(0, c->Acquire(&fence, &m2, sizeof(m2)));
   EXPECT_EQ(m.field1, m2.field1);
   EXPECT_EQ(m.field2, m2.field2);
   EXPECT_EQ(0, c->Release(LocalHandle()));
@@ -552,11 +583,11 @@
 
   // It is illegal to acquire metadata larger than originally requested during
   // buffer allocation.
-  EXPECT_NE(0, c->Acquire(&fence, &e));
+  EXPECT_NE(0, c->Acquire(&fence, &e, sizeof(e)));
 
   // It is ok to acquire metadata smaller than originally requested during
   // buffer allocation.
-  EXPECT_EQ(0, c->Acquire(&fence, &sequence));
+  EXPECT_EQ(0, c->Acquire(&fence, &sequence, sizeof(sequence)));
   EXPECT_EQ(m.field1, sequence);
 }
 
@@ -678,7 +709,7 @@
   std::unique_ptr<ConsumerBuffer> c1 =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c1.get() != nullptr);
-  const uint64_t consumer_state_bit1 = c1->buffer_state_bit();
+  const uint64_t client_state_mask1 = c1->client_state_mask();
 
   DvrNativeBufferMetadata meta;
   EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
@@ -694,8 +725,8 @@
   std::unique_ptr<ConsumerBuffer> c2 =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c2.get() != nullptr);
-  const uint64_t consumer_state_bit2 = c2->buffer_state_bit();
-  EXPECT_NE(consumer_state_bit1, consumer_state_bit2);
+  const uint64_t client_state_mask2 = c2->client_state_mask();
+  EXPECT_NE(client_state_mask1, client_state_mask2);
 
   // The new consumer is available for acquire.
   EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
@@ -710,8 +741,8 @@
   std::unique_ptr<ConsumerBuffer> c3 =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c3.get() != nullptr);
-  const uint64_t consumer_state_bit3 = c3->buffer_state_bit();
-  EXPECT_NE(consumer_state_bit2, consumer_state_bit3);
+  const uint64_t client_state_mask3 = c3->client_state_mask();
+  EXPECT_NE(client_state_mask2, client_state_mask3);
   // The consumer buffer is not acquirable.
   EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
   EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence));
@@ -859,6 +890,7 @@
   int b1_id = b1->id();
   EXPECT_TRUE(b1->IsValid());
   EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
+  EXPECT_NE(b1->client_state_mask(), 0ULL);
 
   auto status_or_handle = b1->Duplicate();
   EXPECT_TRUE(status_or_handle);
@@ -876,18 +908,15 @@
   ASSERT_TRUE(b2 != nullptr);
   EXPECT_TRUE(b2->IsValid());
   EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
+  EXPECT_NE(b2->client_state_mask(), 0ULL);
 
   int b2_id = b2->id();
 
   // These two buffer instances are based on the same physical buffer under the
   // hood, so they should share the same id.
   EXPECT_EQ(b1_id, b2_id);
-  // We use buffer_state_bit() to tell those two instances apart.
-  EXPECT_NE(b1->buffer_state_bit(), b2->buffer_state_bit());
-  EXPECT_NE(b1->buffer_state_bit(), 0ULL);
-  EXPECT_NE(b2->buffer_state_bit(), 0ULL);
-  EXPECT_NE(b1->buffer_state_bit(), kProducerStateBit);
-  EXPECT_NE(b2->buffer_state_bit(), kProducerStateBit);
+  // We use client_state_mask() to tell those two instances apart.
+  EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
 
   // Both buffer instances should be in gained state.
   EXPECT_TRUE(IsBufferGained(b1->buffer_state()));
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index bc6aece..68cc766 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -114,7 +114,7 @@
 
   id_ = new_id;
   cid_ = buffer_desc.buffer_cid();
-  buffer_state_bit_ = buffer_desc.buffer_state_bit();
+  client_state_mask_ = buffer_desc.client_state_mask();
 
   // Note that here the buffer_state, fence_state and active_clients_bit_mask
   // are mapped from shared memory as an atomic object. The std::atomic's
@@ -123,17 +123,17 @@
   buffer_state_ = &metadata_header_->buffer_state;
   ALOGD_IF(TRACE,
            "BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
-           id(), buffer_state_->load());
+           id(), buffer_state_->load(std::memory_order_acquire));
   fence_state_ = &metadata_header_->fence_state;
   ALOGD_IF(TRACE,
            "BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx64 ".", id(),
-           fence_state_->load());
+           fence_state_->load(std::memory_order_acquire));
   active_clients_bit_mask_ = &metadata_header_->active_clients_bit_mask;
   ALOGD_IF(
       TRACE,
       "BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx64
       ".",
-      id(), active_clients_bit_mask_->load());
+      id(), active_clients_bit_mask_->load(std::memory_order_acquire));
 
   return 0;
 }
@@ -169,7 +169,7 @@
       // If ready fence is valid, we put that into the epoll set.
       epoll_event event;
       event.events = EPOLLIN;
-      event.data.u64 = buffer_state_bit();
+      event.data.u64 = client_state_mask();
       pending_fence_fd_ = new_fence.Duplicate();
       if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(),
                     &event) < 0) {
@@ -182,12 +182,12 @@
       }
       // Set bit in fence state to indicate that there is a fence from this
       // producer or consumer.
-      fence_state_->fetch_or(buffer_state_bit());
+      fence_state_->fetch_or(client_state_mask());
     } else {
       // Unset bit in fence state to indicate that there is no fence, so that
       // when consumer to acquire or producer to acquire, it knows no need to
       // check fence for this buffer.
-      fence_state_->fetch_and(~buffer_state_bit());
+      fence_state_->fetch_and(~client_state_mask());
     }
   }
 
diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp
index c9d8554..8e630ec 100644
--- a/libs/vr/libbufferhub/consumer_buffer.cpp
+++ b/libs/vr/libbufferhub/consumer_buffer.cpp
@@ -38,11 +38,11 @@
   // Only check producer bit and this consumer buffer's particular consumer bit.
   // The buffer is can be acquired iff: 1) producer bit is set; 2) consumer bit
   // is not set.
-  uint64_t buffer_state = buffer_state_->load();
-  if (!BufferHubDefs::IsBufferPosted(buffer_state, buffer_state_bit())) {
+  uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
+  if (!BufferHubDefs::IsBufferPosted(buffer_state, client_state_mask())) {
     ALOGE("ConsumerBuffer::LocalAcquire: not posted, id=%d state=%" PRIx64
-          " buffer_state_bit=%" PRIx64 ".",
-          id(), buffer_state, buffer_state_bit());
+          " client_state_mask=%" PRIx64 ".",
+          id(), buffer_state, client_state_mask());
     return -EBUSY;
   }
 
@@ -57,14 +57,15 @@
     out_meta->user_metadata_ptr = 0;
   }
 
-  uint64_t fence_state = fence_state_->load();
+  uint64_t fence_state = fence_state_->load(std::memory_order_acquire);
   // If there is an acquire fence from producer, we need to return it.
-  if (fence_state & BufferHubDefs::kProducerStateBit) {
+  // The producer state bit mask is kFirstClientBitMask for now.
+  if (fence_state & BufferHubDefs::kFirstClientBitMask) {
     *out_fence = shared_acquire_fence_.Duplicate();
   }
 
   // Set the consumer bit unique to this consumer.
-  BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, buffer_state_bit());
+  BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, client_state_mask());
   return 0;
 }
 
@@ -118,7 +119,7 @@
     return error;
 
   // Check invalid state transition.
-  uint64_t buffer_state = buffer_state_->load();
+  uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
   if (!BufferHubDefs::IsBufferAcquired(buffer_state)) {
     ALOGE("ConsumerBuffer::LocalRelease: not acquired id=%d state=%" PRIx64 ".",
           id(), buffer_state);
diff --git a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
index 03f2d95..31bf79d 100644
--- a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
+++ b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
@@ -14,6 +14,10 @@
 
   // Checks if the buffer node is valid.
   virtual bool isValid() = 0;
+
+  // Duplicates the client. Token_out will be set to a new token when succeed,
+  // and not changed when failed.
+  virtual status_t duplicate(uint64_t* outToken) = 0;
 };
 
 // BnInterface for IBufferClient. Should only be created in bufferhub service.
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 282be46..09feb73 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -90,11 +90,13 @@
   int cid() const { return cid_; }
 
   // Returns the buffer buffer state.
-  uint64_t buffer_state() { return buffer_state_->load(); };
+  uint64_t buffer_state() {
+    return buffer_state_->load(std::memory_order_acquire);
+  };
 
   // A state mask which is unique to a buffer hub client among all its siblings
   // sharing the same concrete graphic buffer.
-  uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+  uint64_t client_state_mask() const { return client_state_mask_; }
 
   // The following methods return settings of the first buffer. Currently,
   // it is only possible to create multi-buffer BufferHubBases with the same
@@ -157,7 +159,7 @@
 
   // Client bit mask which indicates the locations of this client object in the
   // buffer_state_.
-  uint64_t buffer_state_bit_{0ULL};
+  uint64_t client_state_mask_{0ULL};
   IonBuffer buffer_;
   IonBuffer metadata_buffer_;
 };
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index 49f9c3e..650da97 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -26,20 +26,21 @@
 // MSB           LSB
 //  |             |
 //  v             v
-// [P|C62|...|C1|C0]
-// Gain'ed state:     [0|..|0|0] -> Exclusively Writable.
-// Post'ed state:     [1|..|0|0]
-// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
-// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
-static constexpr uint64_t kProducerStateBit = 1ULL << 63;
-static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
+// [C62|...|C1|C0|P]
+// Gain'ed state:     [..|0|0|0] -> Exclusively Writable.
+// Post'ed state:     [..|0|0|1]
+// Acquired'ed state: [..|X|X|1] -> At least one bit is set in higher 63 bits
+// Released'ed state: [..|X|X|0] -> At least one bit is set in higher 63 bits
+static constexpr int kMaxNumberOfClients = 64;
+static constexpr uint64_t kFirstClientBitMask = 1ULL;
+static constexpr uint64_t kConsumerStateMask = ~kFirstClientBitMask;
 
 static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
                                      uint64_t clear_mask, uint64_t set_mask) {
   uint64_t old_state;
   uint64_t new_state;
   do {
-    old_state = buffer_state->load();
+    old_state = buffer_state->load(std::memory_order_acquire);
     new_state = (old_state & ~clear_mask) | set_mask;
   } while (!buffer_state->compare_exchange_weak(old_state, new_state));
 }
@@ -48,23 +49,23 @@
 
 static inline bool IsBufferPosted(uint64_t state,
                                   uint64_t consumer_bit = kConsumerStateMask) {
-  return (state & kProducerStateBit) && !(state & consumer_bit);
+  return (state & kFirstClientBitMask) && !(state & consumer_bit);
 }
 
 static inline bool IsBufferAcquired(uint64_t state) {
-  return (state & kProducerStateBit) && (state & kConsumerStateMask);
+  return (state & kFirstClientBitMask) && (state & kConsumerStateMask);
 }
 
 static inline bool IsBufferReleased(uint64_t state) {
-  return !(state & kProducerStateBit) && (state & kConsumerStateMask);
+  return !(state & kFirstClientBitMask) && (state & kConsumerStateMask);
 }
 
-static inline uint64_t FindNextClearedBit(uint64_t bits) {
+static inline uint64_t FindNextAvailableClientStateMask(uint64_t bits) {
   return ~bits - (~bits & (~bits - 1));
 }
 
 static inline uint64_t FindFirstClearedBit() {
-  return FindNextClearedBit(kProducerStateBit);
+  return FindNextAvailableClientStateMask(kFirstClientBitMask);
 }
 
 struct __attribute__((packed, aligned(8))) MetadataHeader {
@@ -94,13 +95,13 @@
   BufferTraits() = default;
   BufferTraits(const native_handle_t* buffer_handle,
                const FileHandleType& metadata_handle, int id,
-               uint64_t buffer_state_bit, uint64_t metadata_size,
+               uint64_t client_state_mask, uint64_t metadata_size,
                uint32_t width, uint32_t height, uint32_t layer_count,
                uint32_t format, uint64_t usage, uint32_t stride,
                const FileHandleType& acquire_fence_fd,
                const FileHandleType& release_fence_fd)
       : id_(id),
-        buffer_state_bit_(buffer_state_bit),
+        client_state_mask_(client_state_mask),
         metadata_size_(metadata_size),
         width_(width),
         height_(height),
@@ -122,9 +123,9 @@
 
   // State mask of the buffer client. Each BufferHubBuffer client backed by the
   // same buffer channel has uniqued state bit among its siblings. For a
-  // producer buffer the bit must be kProducerStateBit; for a consumer the bit
+  // producer buffer the bit must be kFirstClientBitMask; for a consumer the bit
   // must be one of the kConsumerStateMask.
-  uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+  uint64_t client_state_mask() const { return client_state_mask_; }
   uint64_t metadata_size() const { return metadata_size_; }
 
   uint32_t width() { return width_; }
@@ -148,7 +149,7 @@
  private:
   // BufferHub specific traits.
   int id_ = -1;
-  uint64_t buffer_state_bit_;
+  uint64_t client_state_mask_;
   uint64_t metadata_size_;
 
   // Traits for a GraphicBuffer.
@@ -169,10 +170,10 @@
   FileHandleType acquire_fence_fd_;
   FileHandleType release_fence_fd_;
 
-  PDX_SERIALIZABLE_MEMBERS(BufferTraits<FileHandleType>, id_, buffer_state_bit_,
-                           metadata_size_, stride_, width_, height_,
-                           layer_count_, format_, usage_, buffer_handle_,
-                           metadata_handle_, acquire_fence_fd_,
+  PDX_SERIALIZABLE_MEMBERS(BufferTraits<FileHandleType>, id_,
+                           client_state_mask_, metadata_size_, stride_, width_,
+                           height_, layer_count_, format_, usage_,
+                           buffer_handle_, metadata_handle_, acquire_fence_fd_,
                            release_fence_fd_);
 
   BufferTraits(const BufferTraits&) = delete;
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index 7330aa1..5ff4e00 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -99,12 +99,12 @@
  public:
   BufferDescription() = default;
   BufferDescription(const IonBuffer& buffer, const IonBuffer& metadata, int id,
-                    int buffer_cid, uint64_t buffer_state_bit,
+                    int buffer_cid, uint64_t client_state_mask,
                     const FileHandleType& acquire_fence_fd,
                     const FileHandleType& release_fence_fd)
       : id_(id),
         buffer_cid_(buffer_cid),
-        buffer_state_bit_(buffer_state_bit),
+        client_state_mask_(client_state_mask),
         buffer_(buffer, id),
         metadata_(metadata, id),
         acquire_fence_fd_(acquire_fence_fd.Borrow()),
@@ -122,10 +122,8 @@
   int buffer_cid() const { return buffer_cid_; }
 
   // State mask of the buffer client. Each BufferHub client backed by the
-  // same buffer channel has uniqued state bit among its siblings. For a
-  // producer buffer the bit must be kProducerStateBit; for a consumer the bit
-  // must be one of the kConsumerStateMask.
-  uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+  // same buffer channel has uniqued state bit among its siblings.
+  uint64_t client_state_mask() const { return client_state_mask_; }
   FileHandleType take_acquire_fence() { return std::move(acquire_fence_fd_); }
   FileHandleType take_release_fence() { return std::move(release_fence_fd_); }
 
@@ -135,7 +133,7 @@
  private:
   int id_{-1};
   int buffer_cid_{-1};
-  uint64_t buffer_state_bit_{0};
+  uint64_t client_state_mask_{0};
   // Two IonBuffers: one for the graphic buffer and one for metadata.
   NativeBufferHandle<FileHandleType> buffer_;
   NativeBufferHandle<FileHandleType> metadata_;
@@ -145,7 +143,7 @@
   FileHandleType release_fence_fd_;
 
   PDX_SERIALIZABLE_MEMBERS(BufferDescription<FileHandleType>, id_, buffer_cid_,
-                           buffer_state_bit_, buffer_, metadata_,
+                           client_state_mask_, buffer_, metadata_,
                            acquire_fence_fd_, release_fence_fd_);
 
   BufferDescription(const BufferDescription&) = delete;
@@ -314,7 +312,6 @@
     kOpProducerGain,
     kOpConsumerAcquire,
     kOpConsumerRelease,
-    kOpProducerBufferDetach,
     kOpConsumerBufferDetach,
     kOpCreateProducerQueue,
     kOpCreateConsumerQueue,
@@ -344,8 +341,6 @@
   PDX_REMOTE_METHOD(ConsumerAcquire, kOpConsumerAcquire, LocalFence(Void));
   PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease,
                     void(LocalFence release_fence));
-  PDX_REMOTE_METHOD(ProducerBufferDetach, kOpProducerBufferDetach,
-                    LocalChannelHandle(Void));
 
   // Detaches a ConsumerBuffer from an existing producer/consumer set. Can only
   // be called when the consumer is the only consumer and it has exclusive
diff --git a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
index 2044c53..7349779 100644
--- a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
@@ -45,15 +45,6 @@
   // Returns zero on success, or a negative errno code otherwise.
   int Acquire(LocalHandle* ready_fence, void* meta, size_t user_metadata_size);
 
-  // Attempt to retrieve a post event from buffer hub. If successful,
-  // |ready_fence| is set to a fence to wait on until the buffer is ready. This
-  // call will only succeed after the fd is signaled. This returns zero or a
-  // negative unix error code.
-  template <typename Meta>
-  int Acquire(LocalHandle* ready_fence, Meta* meta) {
-    return Acquire(ready_fence, meta, sizeof(*meta));
-  }
-
   // Asynchronously acquires a bufer.
   int AcquireAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
 
diff --git a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
index d2d4d1e..2761416 100644
--- a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
@@ -52,11 +52,14 @@
 
   // Attempt to re-gain the buffer for writing. If |release_fence| is valid, it
   // must be waited on before using the buffer. If it is not valid then the
-  // buffer is free for immediate use. This call will only succeed if the buffer
-  // is in the released state.
-  // This returns zero or a negative unix error code.
-  int Gain(LocalHandle* release_fence);
-  int GainAsync();
+  // buffer is free for immediate use. This call will succeed if the buffer
+  // is in the released state, or in posted state and gain_posted_buffer is
+  // true.
+  //
+  // @param release_fence output fence.
+  // @param gain_posted_buffer whether to gain posted buffer or not.
+  // @return This returns zero or a negative unix error code.
+  int Gain(LocalHandle* release_fence, bool gain_posted_buffer = false);
 
   // Asynchronously marks a released buffer as gained. This method is similar to
   // the synchronous version above, except that it does not wait for BufferHub
@@ -64,7 +67,13 @@
   // the underlying message, no error is returned if this method is called when
   // the buffer is in an incorrect state. Returns zero if sending the message
   // succeeded, or a negative errno code if local error check fails.
-  int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+  // TODO(b/112007999): gain_posted_buffer true is only used to prevent
+  // libdvrtracking from starving when there are non-responding clients. This
+  // gain_posted_buffer param can be removed once libdvrtracking start to use
+  // the new AHardwareBuffer API.
+  int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence,
+                bool gain_posted_buffer = false);
+  int GainAsync();
 
   // Detaches a ProducerBuffer from an existing producer/consumer set. Can only
   // be called when a producer buffer has exclusive access to the buffer (i.e.
@@ -92,7 +101,8 @@
   explicit ProducerBuffer(LocalChannelHandle channel);
 
   // Local state transition helpers.
-  int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+  int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence,
+                bool gain_posted_buffer = false);
   int LocalPost(const DvrNativeBufferMetadata* meta,
                 const LocalHandle& ready_fence);
 };
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index 7b6f77a..f36e169 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -80,7 +80,7 @@
     return error;
 
   // Check invalid state transition.
-  uint64_t buffer_state = buffer_state_->load();
+  uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
   if (!BufferHubDefs::IsBufferGained(buffer_state)) {
     ALOGE("ProducerBuffer::LocalPost: not gained, id=%d state=%" PRIx64 ".",
           id(), buffer_state);
@@ -102,8 +102,9 @@
     return error;
 
   // Set the producer bit atomically to transit into posted state.
+  // The producer state bit mask is kFirstClientBitMask for now.
   BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL,
-                                   BufferHubDefs::kProducerStateBit);
+                                   BufferHubDefs::kFirstClientBitMask);
   return 0;
 }
 
@@ -134,21 +135,22 @@
 }
 
 int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta,
-                              LocalHandle* out_fence) {
-  uint64_t buffer_state = buffer_state_->load();
+                              LocalHandle* out_fence, bool gain_posted_buffer) {
+  uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
   ALOGD_IF(TRACE, "ProducerBuffer::LocalGain: buffer=%d, state=%" PRIx64 ".",
            id(), buffer_state);
 
   if (!out_meta)
     return -EINVAL;
 
-  if (!BufferHubDefs::IsBufferReleased(buffer_state)) {
-    if (BufferHubDefs::IsBufferGained(buffer_state)) {
-      // We don't want to log error when gaining a newly allocated
-      // buffer.
-      ALOGI("ProducerBuffer::LocalGain: already gained id=%d.", id());
-      return -EALREADY;
-    }
+  if (BufferHubDefs::IsBufferGained(buffer_state)) {
+    // We don't want to log error when gaining a newly allocated
+    // buffer.
+    ALOGI("ProducerBuffer::LocalGain: already gained id=%d.", id());
+    return -EALREADY;
+  }
+  if (BufferHubDefs::IsBufferAcquired(buffer_state) ||
+      (BufferHubDefs::IsBufferPosted(buffer_state) && !gain_posted_buffer)) {
     ALOGE("ProducerBuffer::LocalGain: not released id=%d state=%" PRIx64 ".",
           id(), buffer_state);
     return -EBUSY;
@@ -167,7 +169,7 @@
     out_meta->user_metadata_ptr = 0;
   }
 
-  uint64_t fence_state = fence_state_->load();
+  uint64_t fence_state = fence_state_->load(std::memory_order_acquire);
   // If there is an release fence from consumer, we need to return it.
   if (fence_state & BufferHubDefs::kConsumerStateMask) {
     *out_fence = shared_release_fence_.Duplicate();
@@ -180,11 +182,11 @@
   return 0;
 }
 
-int ProducerBuffer::Gain(LocalHandle* release_fence) {
+int ProducerBuffer::Gain(LocalHandle* release_fence, bool gain_posted_buffer) {
   ATRACE_NAME("ProducerBuffer::Gain");
 
   DvrNativeBufferMetadata meta;
-  if (const int error = LocalGain(&meta, release_fence))
+  if (const int error = LocalGain(&meta, release_fence, gain_posted_buffer))
     return error;
 
   auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>();
@@ -194,10 +196,11 @@
 }
 
 int ProducerBuffer::GainAsync(DvrNativeBufferMetadata* out_meta,
-                              LocalHandle* release_fence) {
+                              LocalHandle* release_fence,
+                              bool gain_posted_buffer) {
   ATRACE_NAME("ProducerBuffer::GainAsync");
 
-  if (const int error = LocalGain(out_meta, release_fence))
+  if (const int error = LocalGain(out_meta, release_fence, gain_posted_buffer))
     return error;
 
   return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode));
@@ -226,7 +229,9 @@
   ALOGW("ProducerBuffer::Detach: not supported operation during migration");
   return {};
 
-  uint64_t buffer_state = buffer_state_->load();
+  // TODO(b/112338294) Keep here for reference. Remove it after new logic is
+  // written.
+  /* uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
   if (!BufferHubDefs::IsBufferGained(buffer_state)) {
     // Can only detach a ProducerBuffer when it's in gained state.
     ALOGW("ProducerBuffer::Detach: The buffer (id=%d, state=0x%" PRIx64
@@ -240,7 +245,7 @@
   ALOGE_IF(!status,
            "ProducerBuffer::Detach: Failed to detach buffer (id=%d): %s.", id(),
            status.GetErrorMessage().c_str());
-  return status;
+  return status; */
 }
 
 }  // namespace dvr
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index e1c1aa9..f7942d0 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -69,7 +69,7 @@
       .data = {.u64 = Stuff(-1, BufferHubQueue::kEpollQueueEventIndex)}};
   ret = epoll_fd_.Control(EPOLL_CTL_ADD, event_fd(), &event);
   if (ret < 0) {
-    ALOGE("BufferHubQueue::Initialize: Failed to add event fd to epoll set: %s",
+    ALOGE("%s: Failed to add event fd to epoll set: %s", __FUNCTION__,
           strerror(-ret));
   }
 }
@@ -77,7 +77,7 @@
 Status<void> BufferHubQueue::ImportQueue() {
   auto status = InvokeRemoteMethod<BufferHubRPC::GetQueueInfo>();
   if (!status) {
-    ALOGE("BufferHubQueue::ImportQueue: Failed to import queue: %s",
+    ALOGE("%s: Failed to import queue: %s", __FUNCTION__,
           status.GetErrorMessage().c_str());
     return ErrorStatus(status.error());
   } else {
@@ -136,9 +136,7 @@
       consumer_queue->GetChannel()->TakeChannelParcelable());
 
   if (!queue_parcelable.IsValid()) {
-    ALOGE(
-        "BufferHubQueue::CreateConsumerQueueParcelable: Failed to create "
-        "consumer queue parcelable.");
+    ALOGE("%s: Failed to create consumer queue parcelable.", __FUNCTION__);
     return ErrorStatus(EINVAL);
   }
 
@@ -169,8 +167,7 @@
     }
 
     if (ret < 0 && ret != -EINTR) {
-      ALOGE("BufferHubQueue::WaitForBuffers: Failed to wait for buffers: %s",
-            strerror(-ret));
+      ALOGE("%s: Failed to wait for buffers: %s", __FUNCTION__, strerror(-ret));
       return false;
     }
 
@@ -264,14 +261,14 @@
     // wait will be tried again to acquire the newly imported buffer.
     auto buffer_status = OnBufferAllocated();
     if (!buffer_status) {
-      ALOGE("BufferHubQueue::HandleQueueEvent: Failed to import buffer: %s",
+      ALOGE("%s: Failed to import buffer: %s", __FUNCTION__,
             buffer_status.GetErrorMessage().c_str());
     }
   } else if (events & EPOLLHUP) {
-    ALOGD_IF(TRACE, "BufferHubQueue::HandleQueueEvent: hang up event!");
+    ALOGD_IF(TRACE, "%s: hang up event!", __FUNCTION__);
     hung_up_ = true;
   } else {
-    ALOGW("BufferHubQueue::HandleQueueEvent: Unknown epoll events=%x", events);
+    ALOGW("%s: Unknown epoll events=%x", __FUNCTION__, events);
   }
 
   return {};
@@ -279,12 +276,11 @@
 
 Status<void> BufferHubQueue::AddBuffer(
     const std::shared_ptr<BufferHubBase>& buffer, size_t slot) {
-  ALOGD_IF(TRACE, "BufferHubQueue::AddBuffer: buffer_id=%d slot=%zu",
-           buffer->id(), slot);
+  ALOGD_IF(TRACE, "%s: buffer_id=%d slot=%zu", __FUNCTION__, buffer->id(),
+           slot);
 
   if (is_full()) {
-    ALOGE("BufferHubQueue::AddBuffer queue is at maximum capacity: %zu",
-          capacity_);
+    ALOGE("%s: queue is at maximum capacity: %zu", __FUNCTION__, capacity_);
     return ErrorStatus(E2BIG);
   }
 
@@ -303,7 +299,7 @@
     const int ret =
         epoll_fd_.Control(EPOLL_CTL_ADD, event_source.event_fd, &event);
     if (ret < 0) {
-      ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s",
+      ALOGE("%s: Failed to add buffer to epoll set: %s", __FUNCTION__,
             strerror(-ret));
       return ErrorStatus(-ret);
     }
@@ -315,17 +311,15 @@
 }
 
 Status<void> BufferHubQueue::RemoveBuffer(size_t slot) {
-  ALOGD_IF(TRACE, "BufferHubQueue::RemoveBuffer: slot=%zu", slot);
+  ALOGD_IF(TRACE, "%s: slot=%zu", __FUNCTION__, slot);
 
   if (buffers_[slot]) {
     for (const auto& event_source : buffers_[slot]->GetEventSources()) {
       const int ret =
           epoll_fd_.Control(EPOLL_CTL_DEL, event_source.event_fd, nullptr);
       if (ret < 0) {
-        ALOGE(
-            "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll "
-            "set: %s",
-            strerror(-ret));
+        ALOGE("%s: Failed to remove buffer from epoll set: %s", __FUNCTION__,
+              strerror(-ret));
         return ErrorStatus(-ret);
       }
     }
@@ -343,6 +337,15 @@
 
 Status<void> BufferHubQueue::Enqueue(Entry entry) {
   if (!is_full()) {
+    // Find and remove the enqueued buffer from unavailable_buffers_slot if
+    // exist.
+    auto enqueued_buffer_iter = std::find_if(
+        unavailable_buffers_slot_.begin(), unavailable_buffers_slot_.end(),
+        [&entry](size_t slot) -> bool { return slot == entry.slot; });
+    if (enqueued_buffer_iter != unavailable_buffers_slot_.end()) {
+      unavailable_buffers_slot_.erase(enqueued_buffer_iter);
+    }
+
     available_buffers_.push(std::move(entry));
 
     // Trigger OnBufferAvailable callback if registered.
@@ -351,17 +354,16 @@
 
     return {};
   } else {
-    ALOGE("BufferHubQueue::Enqueue: Buffer queue is full!");
+    ALOGE("%s: Buffer queue is full!", __FUNCTION__);
     return ErrorStatus(E2BIG);
   }
 }
 
 Status<std::shared_ptr<BufferHubBase>> BufferHubQueue::Dequeue(int timeout,
                                                                size_t* slot) {
-  ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(),
-           timeout);
+  ALOGD_IF(TRACE, "%s: count=%zu, timeout=%d", __FUNCTION__, count(), timeout);
 
-  PDX_TRACE_FORMAT("BufferHubQueue::Dequeue|count=%zu|", count());
+  PDX_TRACE_FORMAT("%s|count=%zu|", __FUNCTION__, count());
 
   if (count() == 0) {
     if (!WaitForBuffers(timeout))
@@ -376,6 +378,7 @@
   *slot = entry.slot;
 
   available_buffers_.pop();
+  unavailable_buffers_slot_.push_back(*slot);
 
   return {std::move(buffer)};
 }
@@ -564,7 +567,7 @@
   auto status =
       InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot);
   if (!status) {
-    ALOGE("ProducerQueue::RemoveBuffer: Failed to remove producer buffer: %s",
+    ALOGE("%s: Failed to remove producer buffer: %s", __FUNCTION__,
           status.GetErrorMessage().c_str());
     return status.error_status();
   }
@@ -580,31 +583,81 @@
 
 pdx::Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
     int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
-    pdx::LocalHandle* release_fence) {
+    pdx::LocalHandle* release_fence, bool gain_posted_buffer) {
   ATRACE_NAME("ProducerQueue::Dequeue");
   if (slot == nullptr || out_meta == nullptr || release_fence == nullptr) {
-    ALOGE("ProducerQueue::Dequeue: Invalid parameter.");
+    ALOGE("%s: Invalid parameter.", __FUNCTION__);
     return ErrorStatus(EINVAL);
   }
 
-  auto status = BufferHubQueue::Dequeue(timeout, slot);
-  if (!status)
-    return status.error_status();
-
-  auto buffer = std::static_pointer_cast<BufferProducer>(status.take());
-  const int ret = buffer->GainAsync(out_meta, release_fence);
+  std::shared_ptr<BufferProducer> buffer;
+  Status<std::shared_ptr<BufferHubBase>> dequeue_status =
+      BufferHubQueue::Dequeue(timeout, slot);
+  if (dequeue_status.ok()) {
+    buffer = std::static_pointer_cast<BufferProducer>(dequeue_status.take());
+  } else {
+    if (gain_posted_buffer) {
+      Status<std::shared_ptr<BufferProducer>> dequeue_unacquired_status =
+          ProducerQueue::DequeueUnacquiredBuffer(slot);
+      if (!dequeue_unacquired_status.ok()) {
+        ALOGE("%s: DequeueUnacquiredBuffer returned error: %d", __FUNCTION__,
+              dequeue_unacquired_status.error());
+        return dequeue_unacquired_status.error_status();
+      }
+      buffer = dequeue_unacquired_status.take();
+    } else {
+      return dequeue_status.error_status();
+    }
+  }
+  const int ret =
+      buffer->GainAsync(out_meta, release_fence, gain_posted_buffer);
   if (ret < 0 && ret != -EALREADY)
     return ErrorStatus(-ret);
 
   return {std::move(buffer)};
 }
 
+Status<std::shared_ptr<BufferProducer>> ProducerQueue::DequeueUnacquiredBuffer(
+    size_t* slot) {
+  if (unavailable_buffers_slot_.size() < 1) {
+    ALOGE(
+        "%s: Failed to dequeue un-acquired buffer. All buffer(s) are in "
+        "acquired state if exist.",
+        __FUNCTION__);
+    return ErrorStatus(ENOMEM);
+  }
+
+  // Find the first buffer that is not in acquired state from
+  // unavailable_buffers_slot_.
+  for (auto iter = unavailable_buffers_slot_.begin();
+       iter != unavailable_buffers_slot_.end(); iter++) {
+    std::shared_ptr<BufferProducer> buffer = ProducerQueue::GetBuffer(*iter);
+    if (buffer == nullptr) {
+      ALOGE("%s failed. Buffer slot %d is  null.", __FUNCTION__,
+            static_cast<int>(*slot));
+      return ErrorStatus(EIO);
+    }
+    if (!BufferHubDefs::IsBufferAcquired(buffer->buffer_state())) {
+      *slot = *iter;
+      unavailable_buffers_slot_.erase(iter);
+      unavailable_buffers_slot_.push_back(*slot);
+      ALOGD("%s: Producer queue dequeue unacquired buffer in slot %d",
+            __FUNCTION__, static_cast<int>(*slot));
+      return {std::move(buffer)};
+    }
+  }
+  ALOGE(
+      "%s: Failed to dequeue un-acquired buffer. No un-acquired buffer exist.",
+      __FUNCTION__);
+  return ErrorStatus(EBUSY);
+}
+
 pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() {
   if (capacity() != 0) {
     ALOGE(
-        "ProducerQueue::TakeAsParcelable: producer queue can only be taken out"
-        " as a parcelable when empty. Current queue capacity: %zu",
-        capacity());
+        "%s: producer queue can only be taken out as a parcelable when empty. "
+        "Current queue capacity: %zu",
+        __FUNCTION__, capacity());
     return ErrorStatus(EINVAL);
   }
 
@@ -628,17 +681,16 @@
     : BufferHubQueue(std::move(handle)) {
   auto status = ImportQueue();
   if (!status) {
-    ALOGE("ConsumerQueue::ConsumerQueue: Failed to import queue: %s",
+    ALOGE("%s: Failed to import queue: %s", __FUNCTION__,
           status.GetErrorMessage().c_str());
     Close(-status.error());
   }
 
   auto import_status = ImportBuffers();
   if (import_status) {
-    ALOGI("ConsumerQueue::ConsumerQueue: Imported %zu buffers.",
-          import_status.get());
+    ALOGI("%s: Imported %zu buffers.", __FUNCTION__, import_status.get());
   } else {
-    ALOGE("ConsumerQueue::ConsumerQueue: Failed to import buffers: %s",
+    ALOGE("%s: Failed to import buffers: %s", __FUNCTION__,
           import_status.GetErrorMessage().c_str());
   }
 }
@@ -647,14 +699,11 @@
   auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>();
   if (!status) {
     if (status.error() == EBADR) {
-      ALOGI(
-          "ConsumerQueue::ImportBuffers: Queue is silent, no buffers "
-          "imported.");
+      ALOGI("%s: Queue is silent, no buffers imported.", __FUNCTION__);
       return {0};
     } else {
-      ALOGE(
-          "ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s",
-          status.GetErrorMessage().c_str());
+      ALOGE("%s: Failed to import consumer buffer: %s", __FUNCTION__,
+            status.GetErrorMessage().c_str());
       return status.error_status();
     }
   }
@@ -665,13 +714,13 @@
 
   auto buffer_handle_slots = status.take();
   for (auto& buffer_handle_slot : buffer_handle_slots) {
-    ALOGD_IF(TRACE, "ConsumerQueue::ImportBuffers: buffer_handle=%d",
+    ALOGD_IF(TRACE, ": buffer_handle=%d", __FUNCTION__,
              buffer_handle_slot.first.value());
 
     std::unique_ptr<BufferConsumer> buffer_consumer =
         BufferConsumer::Import(std::move(buffer_handle_slot.first));
     if (!buffer_consumer) {
-      ALOGE("ConsumerQueue::ImportBuffers: Failed to import buffer: slot=%zu",
+      ALOGE("%s: Failed to import buffer: slot=%zu", __FUNCTION__,
             buffer_handle_slot.second);
       last_error = ErrorStatus(EPIPE);
       continue;
@@ -680,7 +729,7 @@
     auto add_status =
         AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second);
     if (!add_status) {
-      ALOGE("ConsumerQueue::ImportBuffers: Failed to add buffer: %s",
+      ALOGE("%s: Failed to add buffer: %s", __FUNCTION__,
             add_status.GetErrorMessage().c_str());
       last_error = add_status;
     } else {
@@ -696,8 +745,8 @@
 
 Status<void> ConsumerQueue::AddBuffer(
     const std::shared_ptr<BufferConsumer>& buffer, size_t slot) {
-  ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
-           id(), buffer->id(), slot);
+  ALOGD_IF(TRACE, "%s: queue_id=%d buffer_id=%d slot=%zu", __FUNCTION__, id(),
+           buffer->id(), slot);
   return BufferHubQueue::AddBuffer(buffer, slot);
 }
 
@@ -706,9 +755,9 @@
     LocalHandle* acquire_fence) {
   if (user_metadata_size != user_metadata_size_) {
     ALOGE(
-        "ConsumerQueue::Dequeue: Metadata size (%zu) for the dequeuing buffer "
-        "does not match metadata size (%zu) for the queue.",
-        user_metadata_size, user_metadata_size_);
+        "%s: Metadata size (%zu) for the dequeuing buffer does not match "
+        "metadata size (%zu) for the queue.",
+        __FUNCTION__, user_metadata_size, user_metadata_size_);
     return ErrorStatus(EINVAL);
   }
 
@@ -723,7 +772,7 @@
     if (metadata_src) {
       memcpy(meta, metadata_src, user_metadata_size);
     } else {
-      ALOGW("ConsumerQueue::Dequeue: no user-defined metadata.");
+      ALOGW("%s: no user-defined metadata.", __FUNCTION__);
     }
   }
 
@@ -735,7 +784,7 @@
     pdx::LocalHandle* acquire_fence) {
   ATRACE_NAME("ConsumerQueue::Dequeue");
   if (slot == nullptr || out_meta == nullptr || acquire_fence == nullptr) {
-    ALOGE("ConsumerQueue::Dequeue: Invalid parameter.");
+    ALOGE("%s: Invalid parameter.", __FUNCTION__);
     return ErrorStatus(EINVAL);
   }
 
@@ -752,19 +801,18 @@
 }
 
 Status<void> ConsumerQueue::OnBufferAllocated() {
-  ALOGD_IF(TRACE, "ConsumerQueue::OnBufferAllocated: queue_id=%d", id());
+  ALOGD_IF(TRACE, "%s: queue_id=%d", __FUNCTION__, id());
 
   auto status = ImportBuffers();
   if (!status) {
-    ALOGE("ConsumerQueue::OnBufferAllocated: Failed to import buffers: %s",
+    ALOGE("%s: Failed to import buffers: %s", __FUNCTION__,
           status.GetErrorMessage().c_str());
     return ErrorStatus(status.error());
   } else if (status.get() == 0) {
-    ALOGW("ConsumerQueue::OnBufferAllocated: No new buffers allocated!");
+    ALOGW("%s: No new buffers allocated!", __FUNCTION__);
     return ErrorStatus(ENOBUFS);
   } else {
-    ALOGD_IF(TRACE,
-             "ConsumerQueue::OnBufferAllocated: Imported %zu consumer buffers.",
+    ALOGD_IF(TRACE, "%s: Imported %zu consumer buffers.", __FUNCTION__,
              status.get());
     return {};
   }
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index c69002d..def7c6b 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -57,10 +57,10 @@
   uint32_t default_width() const { return default_width_; }
 
   // Returns the default buffer height of this buffer queue.
-  uint32_t default_height() const { return static_cast<uint32_t>(default_height_); }
+  uint32_t default_height() const { return default_height_; }
 
   // Returns the default buffer format of this buffer queue.
-  uint32_t default_format() const { return static_cast<uint32_t>(default_format_); }
+  uint32_t default_format() const { return default_format_; }
 
   // Creates a new consumer in handle form for immediate transport over RPC.
   pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(
@@ -208,6 +208,14 @@
   // Size of the metadata that buffers in this queue cary.
   size_t user_metadata_size_{0};
 
+  // Buffers and related data that are available for dequeue.
+  std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
+      available_buffers_;
+
+  // Slot of the buffers that are not available for normal dequeue. For example,
+  // the slot of posted or acquired buffers in the perspective of a producer.
+  std::vector<size_t> unavailable_buffers_slot_;
+
  private:
   void Initialize();
 
@@ -252,10 +260,6 @@
   // queue regardless of its queue position or presence in the ring buffer.
   std::array<std::shared_ptr<BufferHubBase>, kMaxQueueCapacity> buffers_;
 
-  // Buffers and related data that are available for dequeue.
-  std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
-      available_buffers_;
-
   // Keeps track with how many buffers have been added into the queue.
   size_t capacity_{0};
 
@@ -349,11 +353,30 @@
   // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
   // and caller should call Post() once it's done writing to release the buffer
   // to the consumer side.
+  // @return a buffer in gained state, which was originally in released state.
   pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
       int timeout, size_t* slot, pdx::LocalHandle* release_fence);
+
+  // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
+  // and caller should call Post() once it's done writing to release the buffer
+  // to the consumer side.
+  //
+  // @param timeout to dequeue a buffer.
+  // @param slot is the slot of the output BufferProducer.
+  // @param release_fence for gaining a buffer.
+  // @param out_meta metadata of the output buffer.
+  // @param gain_posted_buffer whether to gain posted buffer if no released
+  //     buffer is available to gain.
+  // @return a buffer in gained state, which was originally in released state if
+  //     gain_posted_buffer is false, or in posted/released state if
+  //     gain_posted_buffer is true.
+  // TODO(b/112007999): gain_posted_buffer true is only used to prevent
+  // libdvrtracking from starving when there are non-responding clients. This
+  // gain_posted_buffer param can be removed once libdvrtracking start to use
+  // the new AHardwareBuffer API.
   pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
       int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
-      pdx::LocalHandle* release_fence);
+      pdx::LocalHandle* release_fence, bool gain_posted_buffer = false);
 
   // Enqueues a producer buffer in the queue.
   pdx::Status<void> Enqueue(const std::shared_ptr<BufferProducer>& buffer,
@@ -374,6 +397,16 @@
   // arguments as the constructors.
   explicit ProducerQueue(pdx::LocalChannelHandle handle);
   ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage);
+
+  // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
+  // and caller should call Post() once it's done writing to release the buffer
+  // to the consumer side.
+  //
+  // @param slot the slot of the returned buffer.
+  // @return a buffer in gained state, which was originally in posted state or
+  //     released state.
+  pdx::Status<std::shared_ptr<BufferProducer>> DequeueUnacquiredBuffer(
+      size_t* slot);
 };
 
 class ConsumerQueue : public BufferHubQueue {
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 046df54..c58f55f 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -1,5 +1,6 @@
 #include <base/logging.h>
 #include <binder/Parcel.h>
+#include <dvr/dvr_api.h>
 #include <private/dvr/buffer_hub_client.h>
 #include <private/dvr/buffer_hub_queue_client.h>
 
@@ -122,6 +123,147 @@
   }
 }
 
+TEST_F(BufferHubQueueTest,
+       TestDequeuePostedBufferIfNoAvailableReleasedBuffer_withBufferConsumer) {
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+
+  // Allocate 3 buffers to use.
+  const size_t test_queue_capacity = 3;
+  for (int64_t i = 0; i < test_queue_capacity; i++) {
+    AllocateBuffer();
+  }
+  EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity);
+
+  size_t producer_slot, consumer_slot;
+  LocalHandle fence;
+  DvrNativeBufferMetadata mi, mo;
+
+  // Producer posts 2 buffers and remember their posted sequence.
+  std::deque<size_t> posted_slots;
+  for (int64_t i = 0; i < 2; i++) {
+    auto p1_status =
+        producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
+    EXPECT_TRUE(p1_status.ok());
+    auto p1 = p1_status.take();
+    ASSERT_NE(p1, nullptr);
+
+    // Producer should not be gaining posted buffer when there are still
+    // available buffers to gain.
+    auto found_iter =
+        std::find(posted_slots.begin(), posted_slots.end(), producer_slot);
+    EXPECT_EQ(found_iter, posted_slots.end());
+    posted_slots.push_back(producer_slot);
+
+    // Producer posts the buffer.
+    mi.index = i;
+    EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
+  }
+
+  // Consumer acquires one buffer.
+  auto c1_status =
+      consumer_queue_->Dequeue(kTimeoutMs, &consumer_slot, &mo, &fence);
+  EXPECT_TRUE(c1_status.ok());
+  auto c1 = c1_status.take();
+  ASSERT_NE(c1, nullptr);
+  // Consumer should get the oldest posted buffer. No checks here.
+  // posted_slots[0] should be in acquired state now.
+  EXPECT_EQ(mo.index, 0);
+  // Consumer releases the buffer.
+  EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0);
+  // posted_slots[0] should be in released state now.
+
+  // Producer gain and post 2 buffers.
+  for (int64_t i = 0; i < 2; i++) {
+    auto p1_status =
+        producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
+    EXPECT_TRUE(p1_status.ok());
+    auto p1 = p1_status.take();
+    ASSERT_NE(p1, nullptr);
+
+    // The gained buffer should be the one in released state or the one haven't
+    // been use.
+    EXPECT_NE(posted_slots[1], producer_slot);
+
+    mi.index = i + 2;
+    EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
+  }
+
+  // Producer gains a buffer.
+  auto p1_status =
+      producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
+  EXPECT_TRUE(p1_status.ok());
+  auto p1 = p1_status.take();
+  ASSERT_NE(p1, nullptr);
+
+  // The gained buffer should be the oldest posted buffer.
+  EXPECT_EQ(posted_slots[1], producer_slot);
+
+  // Producer posts the buffer.
+  mi.index = 4;
+  EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
+}
+
+TEST_F(BufferHubQueueTest,
+       TestDequeuePostedBufferIfNoAvailableReleasedBuffer_noBufferConsumer) {
+  ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+
+  // Allocate 4 buffers to use.
+  const size_t test_queue_capacity = 4;
+  for (int64_t i = 0; i < test_queue_capacity; i++) {
+    AllocateBuffer();
+  }
+  EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity);
+
+  // Post all allowed buffers and remember their posted sequence.
+  std::deque<size_t> posted_slots;
+  for (int64_t i = 0; i < test_queue_capacity; i++) {
+    size_t slot;
+    LocalHandle fence;
+    DvrNativeBufferMetadata mi, mo;
+
+    // Producer gains a buffer.
+    auto p1_status =
+        producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true);
+    EXPECT_TRUE(p1_status.ok());
+    auto p1 = p1_status.take();
+    ASSERT_NE(p1, nullptr);
+
+    // Producer should not be gaining posted buffer when there are still
+    // available buffers to gain.
+    auto found_iter = std::find(posted_slots.begin(), posted_slots.end(), slot);
+    EXPECT_EQ(found_iter, posted_slots.end());
+    posted_slots.push_back(slot);
+
+    // Producer posts the buffer.
+    mi.index = i;
+    EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
+  }
+
+  // Gain posted buffers in sequence.
+  const int64_t nb_dequeue_all_times = 2;
+  for (int j = 0; j < nb_dequeue_all_times; ++j) {
+    for (int i = 0; i < test_queue_capacity; ++i) {
+      size_t slot;
+      LocalHandle fence;
+      DvrNativeBufferMetadata mi, mo;
+
+      // Producer gains a buffer.
+      auto p1_status =
+          producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true);
+      EXPECT_TRUE(p1_status.ok());
+      auto p1 = p1_status.take();
+      ASSERT_NE(p1, nullptr);
+
+      // The gained buffer should be the oldest posted buffer.
+      EXPECT_EQ(posted_slots[i], slot);
+
+      // Producer posts the buffer.
+      mi.index = i + test_queue_capacity * (j + 1);
+      EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
+    }
+  }
+}
+
 TEST_F(BufferHubQueueTest, TestProducerConsumer) {
   const size_t kBufferCount = 16;
   size_t slot;
@@ -245,8 +387,8 @@
 
   for (size_t i = 0; i < kBufferCount; i++) {
     Entry* entry = &buffers[i];
-    auto producer_status = producer_queue_->Dequeue(
-        kTimeoutMs, &entry->slot, &mo, &entry->fence);
+    auto producer_status =
+        producer_queue_->Dequeue(kTimeoutMs, &entry->slot, &mo, &entry->fence);
     ASSERT_TRUE(producer_status.ok());
     entry->buffer = producer_status.take();
     ASSERT_NE(nullptr, entry->buffer);
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index 68b8dd7..3769162 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -318,13 +318,7 @@
   PDX_TRACE_NAME("Message::ReplyFileHandle");
   auto svc = service_.lock();
   if (!replied_ && svc) {
-    Status<void> ret;
-
-    if (handle)
-      ret = svc->endpoint()->MessageReply(this, handle.Get());
-    else
-      ret = svc->endpoint()->MessageReply(this, handle.Get());
-
+    Status<void> ret = svc->endpoint()->MessageReply(this, handle.Get());
     replied_ = ret.ok();
     return ret;
   } else {
diff --git a/libs/vr/libpdx/status_tests.cpp b/libs/vr/libpdx/status_tests.cpp
index d4e697c..772c529 100644
--- a/libs/vr/libpdx/status_tests.cpp
+++ b/libs/vr/libpdx/status_tests.cpp
@@ -2,6 +2,8 @@
 
 #include <gtest/gtest.h>
 
+#include <memory>
+
 using android::pdx::ErrorStatus;
 using android::pdx::Status;
 
@@ -84,8 +86,8 @@
   Status<std::unique_ptr<int>> status1;
   Status<std::unique_ptr<int>> status2;
 
-  status1 = Status<std::unique_ptr<int>>{std::unique_ptr<int>{new int{11}}};
-  status2 = Status<std::unique_ptr<int>>{std::unique_ptr<int>{new int{12}}};
+  status1 = Status<std::unique_ptr<int>>{std::make_unique<int>(int{11})};
+  status2 = Status<std::unique_ptr<int>>{std::make_unique<int>(int{12})};
   EXPECT_FALSE(status1.empty());
   EXPECT_FALSE(status2.empty());
   EXPECT_TRUE(status1.ok());
@@ -114,7 +116,7 @@
 }
 
 TEST(Status, Take) {
-  Status<std::unique_ptr<int>> status{std::unique_ptr<int>{new int{123}}};
+  Status<std::unique_ptr<int>> status{std::make_unique<int>(int{123})};
   EXPECT_FALSE(status.empty());
   EXPECT_NE(nullptr, status.get());
 
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
index d500278..9a1d2e5 100644
--- a/libs/vr/libvrflinger/tests/Android.bp
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -34,4 +34,7 @@
     ],
     cppflags: ["-std=c++1z"],
     name: "vrflinger_test",
+
+    // TODO(b/117568153): Temporarily opt out using libcrt.
+    no_libcrt: true,
 }
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 6f792ec..e27f233 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -36,23 +36,12 @@
 #include "egl_platform_entries.h"
 #include "egl_trace.h"
 #include "egldefs.h"
+#include <EGL/eglext_angle.h>
 
 extern "C" {
   android_namespace_t* android_get_exported_namespace(const char*);
 
   // TODO(ianelliott@): Get this from an ANGLE header:
-  typedef enum ANGLEPreference {
-      ANGLE_NO_PREFERENCE = 0,
-      ANGLE_PREFER_NATIVE = 1,
-      ANGLE_PREFER_ANGLE = 2,
-  } ANGLEPreference;
-
-  // TODO(ianelliott@): Get this from an ANGLE header:
-  typedef bool (*fpANGLEUseForApplication)(const char* appName, const char* deviceMfr,
-                                           const char* deviceModel, ANGLEPreference developerOption,
-                                           ANGLEPreference appPreference);
-
-  // TODO(ianelliott@): Get this from an ANGLE header:
   typedef bool (*fpANGLEGetUtilityAPI)(unsigned int* versionToUse);
 
   // TODO(ianelliott@): Get this from an ANGLE header:
@@ -274,10 +263,24 @@
     return (void*)hnd;
 }
 
-void Loader::close(void* driver)
+void Loader::close(egl_connection_t* cnx)
 {
-    driver_t* hnd = (driver_t*)driver;
+    driver_t* hnd = (driver_t*) cnx->dso;
     delete hnd;
+    cnx->dso = nullptr;
+
+    if (cnx->featureSo) {
+        dlclose(cnx->featureSo);
+        cnx->featureSo = nullptr;
+    }
+
+    cnx->angleDecided = false;
+    cnx->useAngle = false;
+
+    if (cnx->vendorEGL) {
+        dlclose(cnx->vendorEGL);
+        cnx->vendorEGL = nullptr;
+    }
 }
 
 void Loader::init_api(void* dso,
@@ -507,16 +510,56 @@
     return nullptr;
 }
 
-static ANGLEPreference getAnglePref(const char* app_pref) {
-    if (app_pref == nullptr)
-        return ANGLE_NO_PREFERENCE;
 
-    if (strcmp(app_pref, "angle") == 0) {
-        return ANGLE_PREFER_ANGLE;
-    } else if (strcmp(app_pref, "native") == 0) {
-        return ANGLE_PREFER_NATIVE;
+static bool check_angle_rules(void* so, const char* app_name) {
+    bool use_angle = false;
+    const int rules_fd = android::GraphicsEnv::getInstance().getAngleRulesFd();
+    const long rules_offset = android::GraphicsEnv::getInstance().getAngleRulesOffset();
+    const long rules_length = android::GraphicsEnv::getInstance().getAngleRulesLength();
+
+    std::string app_name_str = app_name ? app_name : "";
+    char manufacturer[PROPERTY_VALUE_MAX];
+    char model[PROPERTY_VALUE_MAX];
+    property_get("ro.product.manufacturer", manufacturer, "UNSET");
+    property_get("ro.product.model", model, "UNSET");
+
+    fpANGLEGetUtilityAPI ANGLEGetUtilityAPI =
+            (fpANGLEGetUtilityAPI)dlsym(so, "ANGLEGetUtilityAPI");
+
+    if (ANGLEGetUtilityAPI) {
+
+        // Negotiate the interface version by requesting most recent known to the platform
+        unsigned int versionToUse = 1;
+        if ((ANGLEGetUtilityAPI)(&versionToUse)) {
+
+            // Add and remove versions below as needed
+            switch(versionToUse) {
+            case 1: {
+                ALOGV("Using version 1 of ANGLE opt-in/out logic interface");
+                fpAndroidUseANGLEForApplication AndroidUseANGLEForApplication =
+                        (fpAndroidUseANGLEForApplication)dlsym(so, "AndroidUseANGLEForApplication");
+
+                if (AndroidUseANGLEForApplication) {
+                    use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
+                                                                rules_length, app_name_str.c_str(),
+                                                                manufacturer, model);
+                } else {
+                    ALOGW("Cannot find AndroidUseANGLEForApplication in ANGLE feature-support library");
+                }
+            }
+            break;
+            default:
+                ALOGW("Cannot find supported version of ANGLE feature-support library, found version %u", versionToUse);
+            }
+        } else {
+            ALOGW("Cannot use ANGLE feature-support library, it is older than supported by EGL, requested version %u", versionToUse);
+        }
+    } else {
+        ALOGW("Cannot find ANGLEGetUtilityAPI function");
     }
-    return ANGLE_NO_PREFERENCE;
+
+    ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
+    return use_angle;
 }
 
 static void* load_angle(const char* kind, android_namespace_t* ns, egl_connection_t* cnx) {
@@ -524,86 +567,42 @@
     if (strcmp(kind, "EGL") != 0 && strcmp(kind, "GLESv2") != 0 && strcmp(kind, "GLESv1_CM") != 0)
         return nullptr;
 
-    void* so = nullptr;
     std::string name;
     char prop[PROPERTY_VALUE_MAX];
 
-    const char* app_name = android_getAngleAppName();
-    const char* app_pref = android_getAngleAppPref();
-    bool developer_opt_in = android_getAngleDeveloperOptIn();
-    const int rules_fd = android_getAngleRulesFd();
-    const long rules_offset = android_getAngleRulesOffset();
-    const long rules_length = android_getAngleRulesLength();
+    const char* app_name = android::GraphicsEnv::getInstance().getAngleAppName();
+    bool developer_opt_in = android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
 
     // Determine whether or not to use ANGLE:
-    ANGLEPreference developer_option = developer_opt_in ? ANGLE_PREFER_ANGLE : ANGLE_NO_PREFERENCE;
-    bool use_angle = (developer_option == ANGLE_PREFER_ANGLE);
+    bool use_angle = developer_opt_in;
 
     if (use_angle) {
         ALOGV("User set \"Developer Options\" to force the use of ANGLE");
+    } else if (cnx->angleDecided) {
+        use_angle = cnx->useAngle;
     } else {
         // The "Developer Options" value wasn't set to force the use of ANGLE.  Need to temporarily
         // load ANGLE and call the updatable opt-in/out logic:
-        std::string app_name_str = app_name ? app_name : "";
-        char manufacturer[PROPERTY_VALUE_MAX];
-        char model[PROPERTY_VALUE_MAX];
-        property_get("ro.product.manufacturer", manufacturer, "UNSET");
-        property_get("ro.product.model", model, "UNSET");
-        so = load_angle_from_namespace("feature_support", ns);
-        if (so) {
-            ALOGV("Temporarily loaded ANGLE's opt-in/out logic from namespace");
-            bool use_version0_API = false;
-            bool use_version1_API = false;
-            fpANGLEGetUtilityAPI ANGLEGetUtilityAPI =
-                    (fpANGLEGetUtilityAPI)dlsym(so, "ANGLEGetUtilityAPI");
-            if (ANGLEGetUtilityAPI) {
-                unsigned int versionToUse = 1;
-                if ((ANGLEGetUtilityAPI)(&versionToUse)) {
-                    if (versionToUse == 1) {
-                        use_version1_API = true;
-                    } else {
-                        use_version0_API = true;
-                    }
-                }
-            } else {
-                use_version0_API = true;
-            }
-            if (use_version1_API) {
-                // Use the new version 1 API to determine if the
-                // application should use the ANGLE or the native driver.
-                fpAndroidUseANGLEForApplication AndroidUseANGLEForApplication =
-                        (fpAndroidUseANGLEForApplication)dlsym(so, "AndroidUseANGLEForApplication");
-                if (AndroidUseANGLEForApplication) {
-                    use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
-                                                                rules_length, app_name_str.c_str(),
-                                                                manufacturer, model);
-                } else {
-                    ALOGW("Cannot find AndroidUseANGLEForApplication in library");
-                }
-            } else if (use_version0_API) {
-                // Use the old version 0 API to determine if the
-                // application should use the ANGLE or the native driver.
-                fpANGLEUseForApplication ANGLEUseForApplication =
-                        (fpANGLEUseForApplication)dlsym(so, "ANGLEUseForApplication");
-                if (ANGLEUseForApplication) {
-                    ANGLEPreference app_preference = getAnglePref(android_getAngleAppPref());
-                    use_angle = (ANGLEUseForApplication)(app_name_str.c_str(), manufacturer, model,
-                                                         developer_option, app_preference);
-                    ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
-                } else {
-                    ALOGW("Cannot find ANGLEUseForApplication in library");
-                }
-            }
-            ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
-            dlclose(so);
-            so = nullptr;
+
+        // Check if ANGLE is enabled. Workaround for several bugs:
+        // b/119305693 b/119322355 b/119305887
+        // Something is not working correctly in the feature library
+        property_get("debug.angle.enable", prop, "0");
+        if (atoi(prop)) {
+            cnx->featureSo = load_angle_from_namespace("feature_support", ns);
+        }
+        if (cnx->featureSo) {
+            ALOGV("loaded ANGLE's opt-in/out logic from namespace");
+            use_angle = check_angle_rules(cnx->featureSo, app_name);
         } else {
             // We weren't able to load and call the updateable opt-in/out logic.
             // If we can't load the library, there is no ANGLE available.
             use_angle = false;
-            ALOGV("Could not temporarily-load the ANGLE opt-in/out logic, cannot use ANGLE.");
+            ALOGV("Could not load the ANGLE opt-in/out logic, cannot use ANGLE.");
         }
+        cnx->angleDecided = true;
     }
+    void* so = nullptr;
     if (use_angle) {
         so = load_angle_from_namespace(kind, ns);
     }
@@ -611,13 +610,30 @@
     if (so) {
         ALOGV("Loaded ANGLE %s library for %s (instead of native)",
               kind, app_name ? app_name : "nullptr");
-        property_get("debug.angle.backend", prop, "UNSET");
-        ALOGV("ANGLE's backend set to %s", prop);
         property_get("debug.hwui.renderer", prop, "UNSET");
         ALOGV("Skia's renderer set to %s", prop);
         cnx->useAngle = true;
-        // Find and load vendor libEGL for ANGLE
-        if (!cnx->vendorEGL) {
+
+        EGLint angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+
+        char prop[PROPERTY_VALUE_MAX];
+        property_get("debug.angle.backend", prop, "0");
+        switch (atoi(prop)) {
+            case 1:
+                ALOGV("%s: Requesting OpenGLES back-end", __FUNCTION__);
+                angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
+                break;
+            case 2:
+                ALOGV("%s: Requesting Vulkan back-end", __FUNCTION__);
+                angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+                break;
+            default:
+                break;
+        }
+
+        cnx->angleBackend = angleBackendDefault;
+        if (!cnx->vendorEGL && (cnx->angleBackend == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)) {
+            // Find and load vendor libEGL for ANGLE's GL back-end to use.
             cnx->vendorEGL = load_system_driver("EGL");
         }
         return so;
@@ -660,13 +676,13 @@
     ATRACE_CALL();
 
     void* dso = nullptr;
-    android_namespace_t* ns = android_getAngleNamespace();
+    android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
     if (ns) {
         dso = load_angle(kind, ns, cnx);
     }
 #ifndef __ANDROID_VNDK__
     if (!dso) {
-        android_namespace_t* ns = android_getDriverNamespace();
+        android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
         if (ns) {
             dso = load_updated_driver(kind, ns);
         }
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 9cc73f3..392887d 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -51,7 +51,7 @@
     ~Loader();
 
     void* open(egl_connection_t* cnx);
-    void close(void* driver);
+    void close(egl_connection_t* cnx);
 
 private:
     Loader();
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 476b304..a065973 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -128,56 +128,10 @@
     return sDisplay[uintptr_t(disp)].getPlatformDisplay(disp, attrib_list);
 }
 
-static bool addAnglePlatformAttributes(egl_connection_t* const cnx, const EGLAttrib* attrib_list,
+static bool addAnglePlatformAttributes(egl_connection_t* const cnx,
                                        std::vector<EGLAttrib>& attrs) {
     intptr_t vendorEGL = (intptr_t)cnx->vendorEGL;
 
-    EGLint angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
-    if (attrib_list) {
-        while (*attrib_list != EGL_NONE) {
-            EGLAttrib attr = *attrib_list++;
-            EGLAttrib value = *attrib_list++;
-            if (attr == EGL_PLATFORM_ANGLE_TYPE_ANGLE) {
-                switch (value) {
-                    case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
-                        angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
-                        break;
-                    case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
-                    case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
-                        angleBackendDefault = value;
-                        break;
-                    default:
-                        ALOGW("Invalid EGL_PLATFORM_ANGLE_TYPE_ANGLE attribute: 0x%" PRIxPTR,
-                              value);
-                        break;
-                }
-            }
-        }
-    }
-
-    // Allow debug property to override application's
-    char prop[PROPERTY_VALUE_MAX];
-    property_get("debug.angle.backend", prop, "0");
-    switch (atoi(prop)) {
-        case 1:
-            ALOGV("addAnglePlatformAttributes: Requesting OpenGLES back-end");
-            angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
-            break;
-        case 2:
-            ALOGV("addAnglePlatformAttributes: Requesting Vulkan back-end");
-            angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
-            break;
-        default:
-            break;
-    }
-
-    if (cnx->angleBackend == 0) {
-        // Haven't been initialized yet, so set it.
-        cnx->angleBackend = angleBackendDefault;
-    } else if (cnx->angleBackend != angleBackendDefault) {
-        return false;
-    }
-
     attrs.reserve(4 * 2);
 
     attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
@@ -186,6 +140,7 @@
     switch (cnx->angleBackend) {
         case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
             ALOGV("%s: Requesting Vulkan ANGLE back-end", __FUNCTION__);
+            char prop[PROPERTY_VALUE_MAX];
             property_get("debug.angle.validation", prop, "0");
             attrs.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
             attrs.push_back(atoi(prop));
@@ -212,7 +167,7 @@
 // Initialize function ptrs for ANGLE PlatformMethods struct, used for systrace
 bool initializeAnglePlatform(EGLDisplay dpy) {
     // Since we're inside libEGL, use dlsym to lookup fptr for ANGLEGetDisplayPlatform
-    android_namespace_t* ns = android_getAngleNamespace();
+    android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
     const android_dlextinfo dlextinfo = {
             .flags = ANDROID_DLEXT_USE_NAMESPACE,
             .library_namespace = ns,
@@ -260,7 +215,7 @@
             }
         }
 
-        if (!addAnglePlatformAttributes(cnx, attrib_list, attrs)) {
+        if (!addAnglePlatformAttributes(cnx, attrs)) {
             ALOGE("eglGetDisplay(%p) failed: Mismatch display request", display);
             *error = EGL_BAD_PARAMETER;
             return EGL_NO_DISPLAY;
@@ -310,7 +265,12 @@
             if (cnx->egl.eglGetPlatformDisplay) {
                 dpy = cnx->egl.eglGetPlatformDisplay(EGL_PLATFORM_ANDROID_KHR, display,
                                                      attrib_list);
-            } else {
+            }
+
+            // It is possible that eglGetPlatformDisplay does not have a
+            // working implementation for Android platform; in that case,
+            // one last fallback to eglGetDisplay
+            if(dpy == EGL_NO_DISPLAY) {
                 if (attrib_list) {
                     ALOGW("getPlatformDisplay: unexpected attribute list, attributes ignored");
                 }
@@ -320,8 +280,7 @@
 
         disp.dpy = dpy;
         if (dpy == EGL_NO_DISPLAY) {
-            loader.close(cnx->dso);
-            cnx->dso = nullptr;
+            loader.close(cnx);
         }
     }
 
diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp
index 6900b8b..dd8fbfc 100644
--- a/opengl/libs/EGL/egl_layers.cpp
+++ b/opengl/libs/EGL/egl_layers.cpp
@@ -144,8 +144,8 @@
 
 std::string LayerLoader::GetDebugLayers() {
     // Layers can be specified at the Java level in GraphicsEnvironemnt
-    // gpu_debug_layers = layer1:layer2:layerN
-    std::string debug_layers = android_getDebugLayers();
+    // gpu_debug_layers_gles = layer1:layer2:layerN
+    std::string debug_layers = android::GraphicsEnv::getInstance().getDebugLayersGLES();
 
     if (debug_layers.empty()) {
         // Only check system properties if Java settings are empty
@@ -339,7 +339,9 @@
     // Load the layers in reverse order so we start with the driver's entrypoint and work our way up
     for (int32_t i = layers.size() - 1; i >= 0; i--) {
         // Check each layer path for the layer
-        std::vector<std::string> paths = android::base::Split(android_getLayerPaths(), ":");
+        std::vector<std::string> paths =
+                android::base::Split(android::GraphicsEnv::getInstance().getLayerPaths().c_str(),
+                                     ":");
 
         if (!system_path.empty()) {
             // Prepend the system paths so they override other layers
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 1daa4d2..547a669 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -485,58 +485,29 @@
 }
 
 // Returns a list of color spaces understood by the vendor EGL driver.
-static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp,
-                                                android_pixel_format format) {
+static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp) {
     std::vector<EGLint> colorSpaces;
-    if (!dp->hasColorSpaceSupport) return colorSpaces;
 
-    // OpenGL drivers only support sRGB encoding with 8-bit formats.
-    // RGB_888 is never returned by getNativePixelFormat, but is included for completeness.
-    const bool formatSupportsSRGBEncoding =
-        format == HAL_PIXEL_FORMAT_RGBA_8888 || format == HAL_PIXEL_FORMAT_RGBX_8888 ||
-        format == HAL_PIXEL_FORMAT_RGB_888;
-    const bool formatIsFloatingPoint = format == HAL_PIXEL_FORMAT_RGBA_FP16;
+    // sRGB and linear are always supported when color space support is present.
+    colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+    colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
 
-    if (formatSupportsSRGBEncoding) {
-        // sRGB and linear are always supported when color space support is present.
-        colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
-        colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
-        // DCI-P3 uses the sRGB transfer function, so it's only relevant for 8-bit formats.
-        if (findExtension(dp->disp.queryString.extensions,
-                              "EGL_EXT_gl_colorspace_display_p3")) {
-            colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
-        }
+    if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_display_p3")) {
+        colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
     }
-
-    // According to the spec, scRGB is only supported for floating point formats.
-    // For non-linear scRGB, the application is responsible for applying the
-    // transfer function.
-    if (formatIsFloatingPoint) {
-        if (findExtension(dp->disp.queryString.extensions,
-                  "EGL_EXT_gl_colorspace_scrgb")) {
-            colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT);
-        }
-        if (findExtension(dp->disp.queryString.extensions,
-                  "EGL_EXT_gl_colorspace_scrgb_linear")) {
-            colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
-        }
+    if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_scrgb")) {
+        colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT);
     }
-
-    // BT2020 can be used with any pixel format. PQ encoding must be applied by the
-    // application and does not affect the behavior of OpenGL.
-    if (findExtension(dp->disp.queryString.extensions,
-                          "EGL_EXT_gl_colorspace_bt2020_linear")) {
+    if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_scrgb_linear")) {
+        colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
+    }
+    if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_linear")) {
         colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT);
     }
-    if (findExtension(dp->disp.queryString.extensions,
-                          "EGL_EXT_gl_colorspace_bt2020_pq")) {
+    if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_pq")) {
         colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
     }
-
-    // Linear DCI-P3 simply uses different primaries than standard RGB and thus
-    // can be used with any pixel format.
-    if (findExtension(dp->disp.queryString.extensions,
-                          "EGL_EXT_gl_colorspace_display_p3_linear")) {
+    if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_display_p3_linear")) {
         colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT);
     }
     return colorSpaces;
@@ -547,18 +518,32 @@
 // unmodified.
 template <typename AttrType>
 static EGLBoolean processAttributes(egl_display_ptr dp, ANativeWindow* window,
-                                    android_pixel_format format, const AttrType* attrib_list,
-                                    EGLint* colorSpace, std::vector<AttrType>* strippedAttribList) {
+                                    const AttrType* attrib_list, EGLint* colorSpace,
+                                    std::vector<AttrType>* strippedAttribList) {
     for (const AttrType* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
         bool copyAttribute = true;
         if (attr[0] == EGL_GL_COLORSPACE_KHR) {
-            // Fail immediately if the driver doesn't have color space support at all.
-            if (!dp->hasColorSpaceSupport) return false;
+            switch (attr[1]) {
+                case EGL_GL_COLORSPACE_LINEAR_KHR:
+                case EGL_GL_COLORSPACE_SRGB_KHR:
+                case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
+                case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT:
+                case EGL_GL_COLORSPACE_SCRGB_EXT:
+                case EGL_GL_COLORSPACE_BT2020_LINEAR_EXT:
+                case EGL_GL_COLORSPACE_BT2020_PQ_EXT:
+                case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT:
+                    // Fail immediately if the driver doesn't have color space support at all.
+                    if (!dp->hasColorSpaceSupport) return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+                    break;
+                default:
+                    // BAD_ATTRIBUTE if attr is not any of the EGL_GL_COLORSPACE_*
+                    return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+            }
             *colorSpace = static_cast<EGLint>(attr[1]);
 
             // Strip the attribute if the driver doesn't understand it.
             copyAttribute = false;
-            std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp, format);
+            std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp);
             for (auto driverColorSpace : driverColorSpaces) {
                 if (static_cast<EGLint>(attr[1]) == driverColorSpace) {
                     copyAttribute = true;
@@ -585,10 +570,8 @@
 
     // If the passed color space has wide color gamut, check whether the target native window
     // supports wide color.
-    const bool colorSpaceIsNarrow =
-        *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
-        *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR ||
-        *colorSpace == EGL_UNKNOWN;
+    const bool colorSpaceIsNarrow = *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
+            *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR || *colorSpace == EGL_UNKNOWN;
     if (window && !colorSpaceIsNarrow) {
         bool windowSupportsWideColor = true;
         // Ordinarily we'd put a call to native_window_get_wide_color_support
@@ -606,12 +589,12 @@
             ALOGE("processAttributes: invalid window (win=%p) "
                   "failed (%#x) (already connected to another API?)",
                   window, err);
-            return false;
+            return setError(EGL_BAD_NATIVE_WINDOW, EGL_FALSE);
         }
         if (!windowSupportsWideColor) {
             // Application has asked for a wide-color colorspace but
             // wide-color support isn't available on the display the window is on.
-            return false;
+            return setError(EGL_BAD_MATCH, EGL_FALSE);
         }
     }
     return true;
@@ -695,8 +678,7 @@
                 native_window_set_buffers_smpte2086_metadata(s->getNativeWindow(), &smpteMetadata);
         s->resetSmpte2086Metadata();
         if (err != 0) {
-            ALOGE("error setting native window smpte2086 metadata: %s (%d)",
-                  strerror(-err), err);
+            ALOGE("error setting native window smpte2086 metadata: %s (%d)", strerror(-err), err);
             return EGL_FALSE;
         }
     }
@@ -706,8 +688,7 @@
                 native_window_set_buffers_cta861_3_metadata(s->getNativeWindow(), &cta8613Metadata);
         s->resetCta8613Metadata();
         if (err != 0) {
-            ALOGE("error setting native window CTS 861.3 metadata: %s (%d)",
-                  strerror(-err), err);
+            ALOGE("error setting native window CTS 861.3 metadata: %s (%d)", strerror(-err), err);
             return EGL_FALSE;
         }
     }
@@ -749,10 +730,12 @@
     // now select correct colorspace and dataspace based on user's attribute list
     EGLint colorSpace = EGL_UNKNOWN;
     std::vector<AttrType> strippedAttribList;
-    if (!processAttributes<AttrType>(dp, window, format, attrib_list, &colorSpace,
-                                     &strippedAttribList)) {
+    if (!processAttributes<AttrType>(dp, window, attrib_list, &colorSpace, &strippedAttribList)) {
         ALOGE("error invalid colorspace: %d", colorSpace);
-        return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+        if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+        }
+        return EGL_NO_SURFACE;
     }
     attrib_list = strippedAttribList.data();
 
@@ -765,13 +748,14 @@
         }
 
         android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
-        if (dataSpace != HAL_DATASPACE_UNKNOWN) {
-            err = native_window_set_buffers_data_space(window, dataSpace);
-            if (err != 0) {
-                ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err), err);
-                native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
-                return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
-            }
+        // Set dataSpace even if it could be HAL_DATASPACE_UNKNOWN.
+        // HAL_DATASPACE_UNKNOWN is the default value, but it may have changed
+        // at this point.
+        err = native_window_set_buffers_data_space(window, dataSpace);
+        if (err != 0) {
+            ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err), err);
+            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
         }
     }
 
@@ -873,9 +857,8 @@
     return EGL_NO_SURFACE;
 }
 
-EGLSurface eglCreatePbufferSurfaceImpl( EGLDisplay dpy, EGLConfig config,
-                                        const EGLint *attrib_list)
-{
+EGLSurface eglCreatePbufferSurfaceImpl(EGLDisplay dpy, EGLConfig config,
+                                       const EGLint* attrib_list) {
     egl_connection_t* cnx = nullptr;
     egl_display_ptr dp = validate_display_connection(dpy, cnx);
     if (dp) {
@@ -886,35 +869,30 @@
         // Select correct colorspace based on user's attribute list
         EGLint colorSpace = EGL_UNKNOWN;
         std::vector<EGLint> strippedAttribList;
-        if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace,
-                               &strippedAttribList)) {
+        if (!processAttributes(dp, nullptr, attrib_list, &colorSpace, &strippedAttribList)) {
             ALOGE("error invalid colorspace: %d", colorSpace);
-            return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+            return EGL_NO_SURFACE;
         }
         attrib_list = strippedAttribList.data();
 
-        EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
-                dp->disp.dpy, config, attrib_list);
+        EGLSurface surface = cnx->egl.eglCreatePbufferSurface(dp->disp.dpy, config, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s =
-                    new egl_surface_t(dp.get(), config, nullptr, surface,
-                                      getReportedColorSpace(colorSpace), cnx);
+            egl_surface_t* s = new egl_surface_t(dp.get(), config, nullptr, surface,
+                                                 getReportedColorSpace(colorSpace), cnx);
             return s;
         }
     }
     return EGL_NO_SURFACE;
 }
 
-EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface)
-{
+EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface) {
     const egl_display_ptr dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
     SurfaceRef _s(dp.get(), surface);
-    if (!_s.get())
-        return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
 
-    egl_surface_t * const s = get_surface(surface);
+    egl_surface_t* const s = get_surface(surface);
     EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
     if (result == EGL_TRUE) {
         _s.terminate();
@@ -922,17 +900,15 @@
     return result;
 }
 
-EGLBoolean eglQuerySurfaceImpl( EGLDisplay dpy, EGLSurface surface,
-                                EGLint attribute, EGLint *value)
-{
+EGLBoolean eglQuerySurfaceImpl(EGLDisplay dpy, EGLSurface surface, EGLint attribute,
+                               EGLint* value) {
     const egl_display_ptr dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
     SurfaceRef _s(dp.get(), surface);
-    if (!_s.get())
-        return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
 
-    egl_surface_t const * const s = get_surface(surface);
+    egl_surface_t const* const s = get_surface(surface);
     if (s->getColorSpaceAttribute(attribute, value)) {
         return EGL_TRUE;
     } else if (s->getSmpte2086Attribute(attribute, value)) {
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 7c710d5..cca0053 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -76,9 +76,11 @@
     void*               libGles1;
     void*               libGles2;
 
+    bool                angleDecided;
     bool                useAngle;
     EGLint              angleBackend;
     void*               vendorEGL;
+    void*               featureSo;
 };
 // clang-format on
 
diff --git a/opengl/libs/libEGL.map.txt b/opengl/libs/libEGL.map.txt
index fa26e33..b2d7957 100644
--- a/opengl/libs/libEGL.map.txt
+++ b/opengl/libs/libEGL.map.txt
@@ -3,23 +3,30 @@
     eglBindAPI;
     eglBindTexImage;
     eglChooseConfig;
+    eglClientWaitSync; # introduced=29
     eglClientWaitSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
     eglCopyBuffers;
     eglCreateContext;
+    eglCreateImage; # introduced=29
     eglCreateImageKHR;
     eglCreateNativeClientBufferANDROID; # introduced=24
     eglCreatePbufferFromClientBuffer;
     eglCreatePbufferSurface;
     eglCreatePixmapSurface;
+    eglCreatePlatformPixmapSurface; # introduced=29
+    eglCreatePlatformWindowSurface; # introduced=29
     eglCreateStreamFromFileDescriptorKHR; # introduced=23
     eglCreateStreamKHR; # introduced=23
     eglCreateStreamProducerSurfaceKHR; # introduced=23
+    eglCreateSync; # introduced=29
     eglCreateSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
     eglCreateWindowSurface;
     eglDestroyContext;
+    eglDestroyImage; # introduced=29
     eglDestroyImageKHR;
     eglDestroyStreamKHR; # introduced=23
     eglDestroySurface;
+    eglDestroySync; # introduced=29
     eglDestroySyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
     eglDupNativeFenceFDANDROID; # vndk
     eglGetConfigAttrib;
@@ -30,8 +37,10 @@
     eglGetDisplay;
     eglGetError;
     eglGetNativeClientBufferANDROID; # introduced=26
+    eglGetPlatformDisplay; # introduced=29
     eglGetProcAddress;
     eglGetStreamFileDescriptorKHR; # introduced=23
+    eglGetSyncAttrib; # introduced=29
     eglGetSyncAttribKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
     eglGetSystemTimeFrequencyNV; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
     eglGetSystemTimeNV; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
@@ -64,6 +73,7 @@
     eglWaitClient;
     eglWaitGL;
     eglWaitNative;
+    eglWaitSync; # introduced=29
     eglWaitSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
   local:
     *;
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
index f246077..a9e873a 100644
--- a/opengl/tests/EGLTest/Android.bp
+++ b/opengl/tests/EGLTest/Android.bp
@@ -25,6 +25,7 @@
         "libhidltransport",
         "liblog",
         "libutils",
+        "libnativewindow",
     ],
 
     include_dirs: [
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 5927dc1..459b135 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -775,4 +775,169 @@
 
     EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
 }
+
+TEST_F(EGLTest, EGLInvalidColorspaceAttribute) {
+    EGLConfig config;
+
+    ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+    struct DummyConsumer : public BnConsumerListener {
+        void onFrameAvailable(const BufferItem& /* item */) override {}
+        void onBuffersReleased() override {}
+        void onSidebandStreamChanged() override {}
+    };
+
+    // Create a EGLSurface
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    consumer->consumerConnect(new DummyConsumer, false);
+    sp<Surface> mSTC = new Surface(producer);
+    sp<ANativeWindow> mANW = mSTC;
+
+    EGLint winAttrs[] = {
+            // clang-format off
+            EGL_GL_COLORSPACE_KHR, EGL_BACK_BUFFER,
+            EGL_NONE,
+            // clang-format on
+    };
+
+    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+    ASSERT_EQ(EGL_BAD_ATTRIBUTE, eglGetError());
+    ASSERT_EQ(EGL_NO_SURFACE, eglSurface);
+}
+
+TEST_F(EGLTest, EGLUnsupportedColorspaceFormatCombo) {
+    EGLint numConfigs;
+    EGLConfig config;
+    EGLBoolean success;
+
+    const EGLint attrs[] = {
+            // clang-format off
+            EGL_SURFACE_TYPE,             EGL_WINDOW_BIT,
+            EGL_RENDERABLE_TYPE,          EGL_OPENGL_ES2_BIT,
+            EGL_RED_SIZE,                 16,
+            EGL_GREEN_SIZE,               16,
+            EGL_BLUE_SIZE,                16,
+            EGL_ALPHA_SIZE,               16,
+            EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
+            EGL_NONE,
+            // clang-format on
+    };
+    success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(1, numConfigs);
+
+    struct DummyConsumer : public BnConsumerListener {
+        void onFrameAvailable(const BufferItem& /* item */) override {}
+        void onBuffersReleased() override {}
+        void onSidebandStreamChanged() override {}
+    };
+
+    // Create a EGLSurface
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    consumer->consumerConnect(new DummyConsumer, false);
+    sp<Surface> mSTC = new Surface(producer);
+    sp<ANativeWindow> mANW = mSTC;
+
+    const EGLint winAttrs[] = {
+            // clang-format off
+            EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT,
+            EGL_NONE,
+            // clang-format on
+    };
+
+    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+    ASSERT_EQ(EGL_BAD_MATCH, eglGetError());
+    ASSERT_EQ(EGL_NO_SURFACE, eglSurface);
+}
+
+TEST_F(EGLTest, EGLCreateWindowFailAndSucceed) {
+    EGLConfig config;
+
+    ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+    struct DummyConsumer : public BnConsumerListener {
+        void onFrameAvailable(const BufferItem& /* item */) override {}
+        void onBuffersReleased() override {}
+        void onSidebandStreamChanged() override {}
+    };
+
+    // Create a EGLSurface
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    consumer->consumerConnect(new DummyConsumer, false);
+    sp<Surface> mSTC = new Surface(producer);
+    sp<ANativeWindow> mANW = mSTC;
+
+    EGLint winAttrs[] = {
+            // clang-format off
+            EGL_GL_COLORSPACE_KHR, EGL_BACK_BUFFER,
+            EGL_NONE,
+            // clang-format on
+    };
+
+    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+    ASSERT_EQ(EGL_BAD_ATTRIBUTE, eglGetError());
+    ASSERT_EQ(EGL_NO_SURFACE, eglSurface);
+
+    // Now recreate surface with a valid colorspace. Ensure proper cleanup is done
+    // in the first failed attempt (e.g. native_window_api_disconnect).
+    winAttrs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+    eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+    EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
+TEST_F(EGLTest, EGLCreateWindowTwoColorspaces) {
+    EGLConfig config;
+
+    ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
+
+    struct DummyConsumer : public BnConsumerListener {
+        void onFrameAvailable(const BufferItem& /* item */) override {}
+        void onBuffersReleased() override {}
+        void onSidebandStreamChanged() override {}
+    };
+
+    // Create a EGLSurface
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    consumer->consumerConnect(new DummyConsumer, false);
+    sp<Surface> mSTC = new Surface(producer);
+    sp<ANativeWindow> mANW = mSTC;
+
+    const EGLint winAttrs[] = {
+            // clang-format off
+            EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT,
+            EGL_NONE,
+            // clang-format on
+    };
+
+    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+    android_dataspace dataspace = static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(mANW.get()));
+    ASSERT_EQ(dataspace, HAL_DATASPACE_DISPLAY_P3);
+
+    EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+
+    // Now create with default attribute (EGL_GL_COLORSPACE_LINEAR_KHR)
+    eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+    dataspace = static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(mANW.get()));
+    // Make sure the dataspace has been reset to UNKNOWN
+    ASSERT_NE(dataspace, HAL_DATASPACE_DISPLAY_P3);
+
+    EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
 }
diff --git a/opengl/tools/glgen/stubs/egl/EGL15Header.java-if b/opengl/tools/glgen/stubs/egl/EGL15Header.java-if
index 7409d93..859380f 100644
--- a/opengl/tools/glgen/stubs/egl/EGL15Header.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGL15Header.java-if
@@ -20,7 +20,9 @@
  * EGL 1.5
  *
  */
-public class EGL15 {
+public final class EGL15 {
+
+    private EGL15() {};
 
     public static final int EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT            = 0x00000001;
     public static final int EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT   = 0x00000002;
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
new file mode 100644
index 0000000..ca65e02
--- /dev/null
+++ b/services/bufferhub/Android.bp
@@ -0,0 +1,71 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_shared {
+    name: "libbufferhubservice",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    srcs: [
+        "BufferClient.cpp",
+        "BufferHubService.cpp",
+        "BufferNode.cpp",
+    ],
+    header_libs: [
+        "libbufferhub_headers",
+        "libdvr_headers",
+        "libnativewindow_headers",
+        "libpdx_headers",
+    ],
+    shared_libs: [
+        "android.frameworks.bufferhub@1.0",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libui",
+        "libutils",
+    ],
+    export_include_dirs: [
+        "include"
+    ],
+}
+
+cc_binary {
+    name: "android.frameworks.bufferhub@1.0-service",
+    relative_install_path: "hw",
+    srcs: [
+        "main_bufferhub.cpp"
+    ],
+    shared_libs: [
+        "android.frameworks.bufferhub@1.0",
+        "libbufferhubservice",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libui",
+        "libutils",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    init_rc: ["android.frameworks.bufferhub@1.0-service.rc"],
+    vintf_fragments: ["android.frameworks.bufferhub@1.0-service.xml"],
+}
diff --git a/services/bufferhub/BufferClient.cpp b/services/bufferhub/BufferClient.cpp
new file mode 100644
index 0000000..b3662b2
--- /dev/null
+++ b/services/bufferhub/BufferClient.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bufferhub/BufferClient.h>
+#include <hidl/HidlSupport.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using hardware::hidl_handle;
+using hardware::Void;
+
+Return<void> BufferClient::duplicate(duplicate_cb _hidl_cb) {
+    // TODO(b/118614157): implement token generation and registration
+    _hidl_cb(/*token=*/hidl_handle(), /*status=*/BufferHubStatus::NO_ERROR);
+    return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
\ No newline at end of file
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
new file mode 100644
index 0000000..86598e0
--- /dev/null
+++ b/services/bufferhub/BufferHubService.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bufferhub/BufferHubService.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using hardware::Void;
+
+Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& /*description*/,
+                                              const uint32_t /*userMetadataSize*/,
+                                              allocateBuffer_cb _hidl_cb) {
+    // TODO(b/118614333): implement buffer allocation
+    _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::NO_ERROR);
+    return Void();
+}
+
+Return<void> BufferHubService::importBuffer(const hidl_handle& /*nativeHandle*/,
+                                            importBuffer_cb _hidl_cb) {
+    // TODO(b/118614157): implement buffer import
+    _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::NO_ERROR);
+    return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
new file mode 100644
index 0000000..53dd702
--- /dev/null
+++ b/services/bufferhub/BufferNode.cpp
@@ -0,0 +1,99 @@
+#include <errno.h>
+
+#include <bufferhub/BufferNode.h>
+#include <private/dvr/buffer_hub_defs.h>
+#include <ui/GraphicBufferAllocator.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+void BufferNode::InitializeMetadata() {
+    // Using placement new here to reuse shared memory instead of new allocation
+    // Initialize the atomic variables to zero.
+    dvr::BufferHubDefs::MetadataHeader* metadata_header = metadata_.metadata_header();
+    buffer_state_ = new (&metadata_header->buffer_state) std::atomic<uint64_t>(0);
+    fence_state_ = new (&metadata_header->fence_state) std::atomic<uint64_t>(0);
+    active_clients_bit_mask_ =
+            new (&metadata_header->active_clients_bit_mask) std::atomic<uint64_t>(0);
+}
+
+// Allocates a new BufferNode.
+BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+                       uint64_t usage, size_t user_metadata_size) {
+    uint32_t out_stride = 0;
+    // graphicBufferId is not used in GraphicBufferAllocator::allocate
+    // TODO(b/112338294) After move to the service folder, stop using the
+    // hardcoded service name "bufferhub".
+    int ret = GraphicBufferAllocator::get().allocate(width, height, format, layer_count, usage,
+                                                     const_cast<const native_handle_t**>(
+                                                             &buffer_handle_),
+                                                     &out_stride,
+                                                     /*graphicBufferId=*/0,
+                                                     /*requestor=*/"bufferhub");
+
+    if (ret != OK || buffer_handle_ == nullptr) {
+        ALOGE("%s: Failed to allocate buffer: %s", __FUNCTION__, strerror(-ret));
+        return;
+    }
+
+    buffer_desc_.width = width;
+    buffer_desc_.height = height;
+    buffer_desc_.layers = layer_count;
+    buffer_desc_.format = format;
+    buffer_desc_.usage = usage;
+    buffer_desc_.stride = out_stride;
+
+    metadata_ = BufferHubMetadata::Create(user_metadata_size);
+    if (!metadata_.IsValid()) {
+        ALOGE("%s: Failed to allocate metadata.", __FUNCTION__);
+        return;
+    }
+    InitializeMetadata();
+}
+
+// Free the handle
+BufferNode::~BufferNode() {
+    if (buffer_handle_ != nullptr) {
+        status_t ret = GraphicBufferAllocator::get().free(buffer_handle_);
+        if (ret != OK) {
+            ALOGE("%s: Failed to free handle; Got error: %d", __FUNCTION__, ret);
+        }
+    }
+}
+
+uint64_t BufferNode::GetActiveClientsBitMask() const {
+    return active_clients_bit_mask_->load(std::memory_order_acquire);
+}
+
+uint64_t BufferNode::AddNewActiveClientsBitToMask() {
+    uint64_t current_active_clients_bit_mask = GetActiveClientsBitMask();
+    uint64_t client_state_mask = 0ULL;
+    uint64_t updated_active_clients_bit_mask = 0ULL;
+    do {
+        client_state_mask = dvr::BufferHubDefs::FindNextAvailableClientStateMask(
+                current_active_clients_bit_mask);
+        if (client_state_mask == 0ULL) {
+            ALOGE("%s: reached the maximum number of channels per buffer node: 32.", __FUNCTION__);
+            errno = E2BIG;
+            return 0ULL;
+        }
+        updated_active_clients_bit_mask = current_active_clients_bit_mask | client_state_mask;
+    } while (!(active_clients_bit_mask_->compare_exchange_weak(current_active_clients_bit_mask,
+                                                               updated_active_clients_bit_mask,
+                                                               std::memory_order_acq_rel,
+                                                               std::memory_order_acquire)));
+    return client_state_mask;
+}
+
+void BufferNode::RemoveClientsBitFromMask(const uint64_t& value) {
+    active_clients_bit_mask_->fetch_and(~value);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
diff --git a/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc b/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc
new file mode 100644
index 0000000..36fbede
--- /dev/null
+++ b/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc
@@ -0,0 +1,6 @@
+service system_bufferhub /system/bin/hw/android.frameworks.bufferhub@1.0-service
+  class hal animation
+  user system
+  group system graphics
+  onrestart restart surfaceflinger
+  writepid /dev/cpuset/system-background/tasks
diff --git a/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml b/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml
new file mode 100644
index 0000000..bd958d3
--- /dev/null
+++ b/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+    <hal>
+        <name>android.frameworks.bufferhub</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IBufferHub</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/services/bufferhub/include/bufferhub/BufferClient.h b/services/bufferhub/include/bufferhub/BufferClient.h
new file mode 100644
index 0000000..14ea95c
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/BufferClient.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H
+#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H
+
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using hardware::Return;
+
+class BufferClient : public IBufferClient {
+public:
+    Return<void> duplicate(duplicate_cb _hidl_cb) override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
new file mode 100644
index 0000000..5e0cff0
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
+#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
+
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::Return;
+using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
+
+class BufferHubService : public IBufferHub {
+public:
+    Return<void> allocateBuffer(const HardwareBufferDescription& description,
+                                const uint32_t userMetadataSize,
+                                allocateBuffer_cb _hidl_cb) override;
+    Return<void> importBuffer(const hidl_handle& nativeHandle, importBuffer_cb _hidl_cb) override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
+
+#endif // ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
diff --git a/services/bufferhub/include/bufferhub/BufferNode.h b/services/bufferhub/include/bufferhub/BufferNode.h
new file mode 100644
index 0000000..ffeacac
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/BufferNode.h
@@ -0,0 +1,84 @@
+#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_
+#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_
+
+#include <android/hardware_buffer.h>
+#include <ui/BufferHubMetadata.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+class BufferNode {
+public:
+    // Allocates a new BufferNode.
+    BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+               uint64_t usage, size_t user_metadata_size);
+
+    ~BufferNode();
+
+    // Returns whether the object holds a valid metadata.
+    bool IsValid() const { return metadata_.IsValid(); }
+
+    size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
+
+    // Accessors of the buffer description and handle
+    const native_handle_t* buffer_handle() const { return buffer_handle_; }
+    const AHardwareBuffer_Desc& buffer_desc() const { return buffer_desc_; }
+
+    // Accessors of metadata.
+    const BufferHubMetadata& metadata() const { return metadata_; }
+
+    // Gets the current value of active_clients_bit_mask in metadata_ with
+    // std::memory_order_acquire, so that all previous releases of
+    // active_clients_bit_mask from all threads will be returned here.
+    uint64_t GetActiveClientsBitMask() const;
+
+    // Find and add a new client_state_mask to active_clients_bit_mask in
+    // metadata_.
+    // Return the new client_state_mask that is added to active_clients_bit_mask.
+    // Return 0ULL if there are already 32 bp clients of the buffer.
+    uint64_t AddNewActiveClientsBitToMask();
+
+    // Removes the value from active_clients_bit_mask in metadata_ with
+    // std::memory_order_release, so that the change will be visible to any
+    // acquire of active_clients_bit_mask_ in any threads after the succeed of
+    // this operation.
+    void RemoveClientsBitFromMask(const uint64_t& value);
+
+private:
+    // Helper method for constructors to initialize atomic metadata header
+    // variables in shared memory.
+    void InitializeMetadata();
+
+    // Gralloc buffer handles.
+    native_handle_t* buffer_handle_;
+    AHardwareBuffer_Desc buffer_desc_;
+
+    // Metadata in shared memory.
+    BufferHubMetadata metadata_;
+
+    // The following variables are atomic variables in metadata_ that are visible
+    // to Bn object and Bp objects. Please find more info in
+    // BufferHubDefs::MetadataHeader.
+
+    // buffer_state_ tracks the state of the buffer. Buffer can be in one of these
+    // four states: gained, posted, acquired, released.
+    std::atomic<uint64_t>* buffer_state_ = nullptr;
+
+    // TODO(b/112012161): add comments to fence_state_.
+    std::atomic<uint64_t>* fence_state_ = nullptr;
+
+    // active_clients_bit_mask_ tracks all the bp clients of the buffer. It is the
+    // union of all client_state_mask of all bp clients.
+    std::atomic<uint64_t>* active_clients_bit_mask_ = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
+
+#endif // ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_
diff --git a/services/bufferhub/main_bufferhub.cpp b/services/bufferhub/main_bufferhub.cpp
new file mode 100644
index 0000000..084460d
--- /dev/null
+++ b/services/bufferhub/main_bufferhub.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bufferhub/BufferHubService.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+#include <log/log.h>
+
+using android::sp;
+using android::frameworks::bufferhub::V1_0::IBufferHub;
+using android::frameworks::bufferhub::V1_0::implementation::BufferHubService;
+
+int main(int /*argc*/, char** /*argv*/) {
+    ALOGI("Bootstrap bufferhub HIDL service.");
+
+    android::hardware::configureRpcThreadpool(/*numThreads=*/1, /*willJoin=*/true);
+
+    sp<IBufferHub> service = new BufferHubService();
+    LOG_ALWAYS_FATAL_IF(service->registerAsService() != android::OK, "Failed to register service");
+
+    android::hardware::joinRpcThreadpool();
+
+    return 0;
+}
diff --git a/services/bufferhub/tests/Android.bp b/services/bufferhub/tests/Android.bp
new file mode 100644
index 0000000..cef31f6
--- /dev/null
+++ b/services/bufferhub/tests/Android.bp
@@ -0,0 +1,24 @@
+cc_test {
+    name: "BufferNode_test",
+    srcs: ["BufferNode_test.cpp"],
+    cflags: [
+        "-DLOG_TAG=\"BufferNode_test\"",
+        "-DTRACE=0",
+        "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+    ],
+    header_libs: [
+        "libbufferhub_headers",
+        "libdvr_headers",
+        "libnativewindow_headers",
+        "libpdx_headers",
+    ],
+    shared_libs: [
+        "libbufferhubservice",
+        "libui",
+    ],
+    static_libs: [
+        "libgmock",
+    ],
+    // TODO(b/117568153): Temporarily opt out using libcrt.
+    no_libcrt: true,
+}
\ No newline at end of file
diff --git a/services/bufferhub/tests/BufferNode_test.cpp b/services/bufferhub/tests/BufferNode_test.cpp
new file mode 100644
index 0000000..df31d78
--- /dev/null
+++ b/services/bufferhub/tests/BufferNode_test.cpp
@@ -0,0 +1,110 @@
+#include <bufferhub/BufferNode.h>
+#include <errno.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <ui/GraphicBufferMapper.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+namespace {
+
+using testing::NotNull;
+
+const uint32_t kWidth = 640;
+const uint32_t kHeight = 480;
+const uint32_t kLayerCount = 1;
+const uint32_t kFormat = 1;
+const uint64_t kUsage = 0;
+const size_t kUserMetadataSize = 0;
+const size_t kMaxClientsCount = dvr::BufferHubDefs::kMaxNumberOfClients;
+
+class BufferNodeTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        buffer_node =
+                new BufferNode(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+        ASSERT_TRUE(buffer_node->IsValid());
+    }
+
+    void TearDown() override {
+        if (buffer_node != nullptr) {
+            delete buffer_node;
+        }
+    }
+
+    BufferNode* buffer_node = nullptr;
+};
+
+TEST_F(BufferNodeTest, TestCreateBufferNode) {
+    EXPECT_EQ(buffer_node->user_metadata_size(), kUserMetadataSize);
+    // Test the handle just allocated is good (i.e. able to be imported)
+    GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+    const native_handle_t* outHandle;
+    status_t ret =
+            mapper.importBuffer(buffer_node->buffer_handle(), buffer_node->buffer_desc().width,
+                                buffer_node->buffer_desc().height,
+                                buffer_node->buffer_desc().layers,
+                                buffer_node->buffer_desc().format, buffer_node->buffer_desc().usage,
+                                buffer_node->buffer_desc().stride, &outHandle);
+    EXPECT_EQ(ret, OK);
+    EXPECT_THAT(outHandle, NotNull());
+}
+
+TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_twoNewClients) {
+    uint64_t new_client_state_mask_1 = buffer_node->AddNewActiveClientsBitToMask();
+    EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), new_client_state_mask_1);
+
+    // Request and add a new client_state_mask again.
+    // Active clients bit mask should be the union of the two new
+    // client_state_masks.
+    uint64_t new_client_state_mask_2 = buffer_node->AddNewActiveClientsBitToMask();
+    EXPECT_EQ(buffer_node->GetActiveClientsBitMask(),
+              new_client_state_mask_1 | new_client_state_mask_2);
+}
+
+TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_32NewClients) {
+    uint64_t new_client_state_mask = 0ULL;
+    uint64_t current_mask = 0ULL;
+    uint64_t expected_mask = 0ULL;
+
+    for (int i = 0; i < kMaxClientsCount; ++i) {
+        new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
+        EXPECT_NE(new_client_state_mask, 0);
+        EXPECT_FALSE(new_client_state_mask & current_mask);
+        expected_mask = current_mask | new_client_state_mask;
+        current_mask = buffer_node->GetActiveClientsBitMask();
+        EXPECT_EQ(current_mask, expected_mask);
+    }
+
+    // Method should fail upon requesting for more than maximum allowable clients.
+    new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
+    EXPECT_EQ(new_client_state_mask, 0ULL);
+    EXPECT_EQ(errno, E2BIG);
+}
+
+TEST_F(BufferNodeTest, TestRemoveActiveClientsBitFromMask) {
+    buffer_node->AddNewActiveClientsBitToMask();
+    uint64_t current_mask = buffer_node->GetActiveClientsBitMask();
+    uint64_t new_client_state_mask = buffer_node->AddNewActiveClientsBitToMask();
+    EXPECT_NE(buffer_node->GetActiveClientsBitMask(), current_mask);
+
+    buffer_node->RemoveClientsBitFromMask(new_client_state_mask);
+    EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
+
+    // Remove the test_mask again to the active client bit mask should not modify
+    // the value of active clients bit mask.
+    buffer_node->RemoveClientsBitFromMask(new_client_state_mask);
+    EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
+}
+
+} // namespace
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
new file mode 100644
index 0000000..250bbee
--- /dev/null
+++ b/services/gpuservice/Android.bp
@@ -0,0 +1,74 @@
+filegroup {
+    name: "gpuservice_sources",
+    srcs: [
+        "GpuService.cpp",
+    ],
+}
+
+filegroup {
+    name: "gpuservice_binary_sources",
+    srcs: ["main_gpuservice.cpp"],
+}
+
+cc_defaults {
+    name: "gpuservice_defaults",
+    cflags: [
+        "-DLOG_TAG=\"GpuService\"",
+        "-Wall",
+        "-Werror",
+        "-Wformat",
+        "-Wthread-safety",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+    cppflags: ["-std=c++1z"],
+    srcs: [
+        ":gpuservice_sources",
+    ],
+    include_dirs: [
+        "frameworks/native/vulkan/vkjson",
+        "frameworks/native/vulkan/include",
+    ],
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libutils",
+        "libvulkan",
+    ],
+    static_libs: [
+        "libvkjson",
+    ],
+}
+
+cc_defaults {
+    name: "gpuservice_production_defaults",
+    defaults: ["gpuservice_defaults"],
+    cflags: [
+        "-fvisibility=hidden",
+        "-fwhole-program-vtables", // requires ThinLTO
+    ],
+    lto: {
+        thin: true,
+    },
+}
+
+cc_defaults {
+    name: "gpuservice_binary",
+    defaults: ["gpuservice_defaults"],
+    whole_static_libs: [
+        "libsigchain",
+    ],
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+    ldflags: ["-Wl,--export-dynamic"],
+}
+
+cc_binary {
+    name: "gpuservice",
+    defaults: ["gpuservice_binary"],
+    init_rc: ["gpuservice.rc"],
+    srcs: [":gpuservice_binary_sources"],
+}
diff --git a/services/surfaceflinger/GpuService.cpp b/services/gpuservice/GpuService.cpp
similarity index 83%
rename from services/surfaceflinger/GpuService.cpp
rename to services/gpuservice/GpuService.cpp
index 71052fb..e4ca6bc 100644
--- a/services/surfaceflinger/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -23,10 +23,7 @@
 
 namespace android {
 
-// ----------------------------------------------------------------------------
-
-class BpGpuService : public BpInterface<IGpuService>
-{
+class BpGpuService : public BpInterface<IGpuService> {
 public:
     explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
 };
@@ -34,19 +31,15 @@
 IMPLEMENT_META_INTERFACE(GpuService, "android.ui.IGpuService");
 
 status_t BnGpuService::onTransact(uint32_t code, const Parcel& data,
-        Parcel* reply, uint32_t flags)
-{
+        Parcel* reply, uint32_t flags) {
     status_t status;
     switch (code) {
     case SHELL_COMMAND_TRANSACTION: {
         int in = data.readFileDescriptor();
         int out = data.readFileDescriptor();
         int err = data.readFileDescriptor();
-        int argc = data.readInt32();
-        Vector<String16> args;
-        for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
-           args.add(data.readString16());
-        }
+        std::vector<String16> args;
+        data.readString16Vector(&args);
         sp<IBinder> unusedCallback;
         sp<IResultReceiver> resultReceiver;
         if ((status = data.readNullableStrongBinder(&unusedCallback)) != OK)
@@ -64,20 +57,17 @@
     }
 }
 
-// ----------------------------------------------------------------------------
-
 namespace {
     status_t cmd_help(int out);
     status_t cmd_vkjson(int out, int err);
 }
 
-const char* const GpuService::SERVICE_NAME = "gpu";
+const char* const GpuService::SERVICE_NAME = "gpuservice";
 
-GpuService::GpuService() {}
+GpuService::GpuService() = default;
 
 status_t GpuService::shellCommand(int /*in*/, int out, int err,
-        Vector<String16>& args)
-{
+                                  std::vector<String16>& args) {
     ALOGV("GpuService::shellCommand");
     for (size_t i = 0, n = args.size(); i < n; i++)
         ALOGV("  arg[%zu]: '%s'", i, String8(args[i]).string());
@@ -93,8 +83,6 @@
     return BAD_VALUE;
 }
 
-// ----------------------------------------------------------------------------
-
 namespace {
 
 status_t cmd_help(int out) {
diff --git a/services/surfaceflinger/GpuService.h b/services/gpuservice/GpuService.h
similarity index 80%
rename from services/surfaceflinger/GpuService.h
rename to services/gpuservice/GpuService.h
index b8c28d2..e2b396e 100644
--- a/services/surfaceflinger/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_GPUSERVICE_H
 #define ANDROID_GPUSERVICE_H
 
+#include <vector>
+
 #include <binder/IInterface.h>
 #include <cutils/compiler.h>
 
@@ -34,22 +36,21 @@
 class BnGpuService: public BnInterface<IGpuService> {
 protected:
     virtual status_t shellCommand(int in, int out, int err,
-        Vector<String16>& args) = 0;
+                                  std::vector<String16>& args) = 0;
 
-    virtual status_t onTransact(uint32_t code, const Parcel& data,
+    status_t onTransact(uint32_t code, const Parcel& data,
             Parcel* reply, uint32_t flags = 0) override;
 };
 
-class GpuService : public BnGpuService
-{
+class GpuService : public BnGpuService {
 public:
     static const char* const SERVICE_NAME ANDROID_API;
 
     GpuService() ANDROID_API;
 
 protected:
-    virtual status_t shellCommand(int in, int out, int err,
-        Vector<String16>& args) override;
+    status_t shellCommand(int in, int out, int err,
+                          std::vector<String16>& args) override;
 };
 
 } // namespace android
diff --git a/services/gpuservice/gpuservice.rc b/services/gpuservice/gpuservice.rc
new file mode 100644
index 0000000..d23cf46
--- /dev/null
+++ b/services/gpuservice/gpuservice.rc
@@ -0,0 +1,4 @@
+service gpuservice /system/bin/gpuservice
+    class core
+    user gpu_service
+    group graphics
diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp
new file mode 100644
index 0000000..64aafca
--- /dev/null
+++ b/services/gpuservice/main_gpuservice.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <sys/resource.h>
+#include "GpuService.h"
+
+using namespace android;
+
+int main(int /* argc */, char** /* argv */) {
+    signal(SIGPIPE, SIG_IGN);
+
+    // publish GpuService
+    sp<GpuService> gpuservice = new GpuService();
+    sp<IServiceManager> sm(defaultServiceManager());
+    sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
+
+    // limit the number of binder threads to 4.
+    ProcessState::self()->setThreadPoolMaxThreadCount(4);
+
+    // start the thread pool
+    sp<ProcessState> ps(ProcessState::self());
+    ps->startThreadPool();
+    ps->giveThreadPoolName();
+    IPCThreadState::self()->joinThreadPool();
+
+    return 0;
+}
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 622a623..9a65452 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -41,8 +41,6 @@
         "-Wall",
         "-Wextra",
         "-Werror",
-        // Allow implicit fallthroughs in InputReader.cpp until they are fixed.
-        "-Wno-error=implicit-fallthrough",
         "-Wno-unused-parameter",
         // TODO: Move inputflinger to its own process and mark it hidden
         //-fvisibility=hidden
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index a964d29..1a1dabb 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -147,8 +147,7 @@
         fd(fd), id(id), path(path), identifier(identifier),
         classes(0), configuration(nullptr), virtualKeyMap(nullptr),
         ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0),
-        timestampOverrideSec(0), timestampOverrideUsec(0), enabled(true),
-        isVirtual(fd < 0) {
+        enabled(true), isVirtual(fd < 0) {
     memset(keyBitmask, 0, sizeof(keyBitmask));
     memset(absBitmask, 0, sizeof(absBitmask));
     memset(relBitmask, 0, sizeof(relBitmask));
@@ -871,31 +870,6 @@
                                 (int) iev.time.tv_sec, (int) iev.time.tv_usec,
                                 iev.type, iev.code, iev.value);
 
-                        // Some input devices may have a better concept of the time
-                        // when an input event was actually generated than the kernel
-                        // which simply timestamps all events on entry to evdev.
-                        // This is a custom Android extension of the input protocol
-                        // mainly intended for use with uinput based device drivers.
-                        if (iev.type == EV_MSC) {
-                            if (iev.code == MSC_ANDROID_TIME_SEC) {
-                                device->timestampOverrideSec = iev.value;
-                                continue;
-                            } else if (iev.code == MSC_ANDROID_TIME_USEC) {
-                                device->timestampOverrideUsec = iev.value;
-                                continue;
-                            }
-                        }
-                        if (device->timestampOverrideSec || device->timestampOverrideUsec) {
-                            iev.time.tv_sec = device->timestampOverrideSec;
-                            iev.time.tv_usec = device->timestampOverrideUsec;
-                            if (iev.type == EV_SYN && iev.code == SYN_REPORT) {
-                                device->timestampOverrideSec = 0;
-                                device->timestampOverrideUsec = 0;
-                            }
-                            ALOGV("applied override time %d.%06d",
-                                    int(iev.time.tv_sec), int(iev.time.tv_usec));
-                        }
-
                         // Use the time specified in the event instead of the current time
                         // so that downstream code can get more accurate estimates of
                         // event dispatch latency from the time the event is enqueued onto
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index ea663b7..62ce47c 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -42,20 +42,6 @@
 #define BTN_FIRST 0x100  // first button code
 #define BTN_LAST 0x15f   // last button code
 
-/*
- * These constants are used privately in Android to pass raw timestamps
- * through evdev from uinput device drivers because there is currently no
- * other way to transfer this information.  The evdev driver automatically
- * timestamps all input events with the time they were posted and clobbers
- * whatever information was passed in.
- *
- * For the purposes of this hack, the timestamp is specified in the
- * CLOCK_MONOTONIC timebase and is split into two EV_MSC events specifying
- * seconds and microseconds.
- */
-#define MSC_ANDROID_TIME_SEC 0x6
-#define MSC_ANDROID_TIME_USEC 0x7
-
 namespace android {
 
 enum {
@@ -371,9 +357,6 @@
 
         int32_t controllerNumber;
 
-        int32_t timestampOverrideSec;
-        int32_t timestampOverrideUsec;
-
         Device(int fd, int32_t id, const std::string& path,
                 const InputDeviceIdentifier& identifier);
         ~Device();
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 2cad986..2e984d9 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2545,6 +2545,9 @@
     uint32_t policyFlags = args->policyFlags;
     int32_t flags = args->flags;
     int32_t metaState = args->metaState;
+    // InputDispatcher tracks and generates key repeats on behalf of
+    // whatever notifies it, so repeatCount should always be set to 0
+    constexpr int32_t repeatCount = 0;
     if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
         policyFlags |= POLICY_FLAG_VIRTUAL;
         flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
@@ -2560,7 +2563,7 @@
 
     KeyEvent event;
     event.initialize(args->deviceId, args->source, args->displayId, args->action,
-            flags, keyCode, args->scanCode, metaState, 0,
+            flags, keyCode, args->scanCode, metaState, repeatCount,
             args->downTime, args->eventTime);
 
     android::base::Timer t;
@@ -2585,7 +2588,6 @@
             mLock.lock();
         }
 
-        int32_t repeatCount = 0;
         KeyEntry* newEntry = new KeyEntry(args->eventTime,
                 args->deviceId, args->source, args->displayId, policyFlags,
                 args->action, flags, keyCode, args->scanCode,
@@ -2756,7 +2758,7 @@
         accelerateMetaShortcuts(keyEvent.getDeviceId(), action,
                 /*byref*/ keyCode, /*byref*/ metaState);
         keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(),
-            action, flags, keyCode, keyEvent.getScanCode(), metaState, 0,
+            action, flags, keyCode, keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(),
             keyEvent.getDownTime(), keyEvent.getEventTime());
 
         if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 0b73be0..869bd71 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -1041,7 +1041,7 @@
 
 void InputDevice::dump(std::string& dump) {
     InputDeviceInfo deviceInfo;
-    getDeviceInfo(& deviceInfo);
+    getDeviceInfo(&deviceInfo);
 
     dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(),
             deviceInfo.getDisplayName().c_str());
@@ -2612,7 +2612,7 @@
             // Should not happen during first time configuration.
             ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER");
             mParameters.mode = Parameters::MODE_POINTER;
-            // fall through.
+            [[fallthrough]];
         case Parameters::MODE_POINTER:
             mSource = AINPUT_SOURCE_MOUSE;
             mXPrecision = 1.0f;
diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp
index f1d3726..2da2a70 100644
--- a/services/inputflinger/host/InputFlinger.cpp
+++ b/services/inputflinger/host/InputFlinger.cpp
@@ -53,7 +53,7 @@
     if ((uid != AID_SHELL)
             && !PermissionCache::checkPermission(sDumpPermission, pid, uid)) {
         result.appendFormat("Permission Denial: "
-                "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
+                "can't dump InputFlinger from pid=%d, uid=%d\n", pid, uid);
     } else {
         dumpInternal(result);
     }
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 707f3c5..6114f51 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1082,7 +1082,7 @@
 
 // --- InputReaderPolicyTest ---
 class InputReaderPolicyTest : public testing::Test {
-    protected:
+protected:
     sp<FakeInputReaderPolicy> mFakePolicy;
 
     virtual void SetUp() {
@@ -1101,7 +1101,7 @@
  * Such configuration is not currently allowed.
  */
 TEST_F(InputReaderPolicyTest, Viewports_GetCleared) {
-    const std::string uniqueId = "local:0";
+    static const std::string uniqueId = "local:0";
 
     // We didn't add any viewports yet, so there shouldn't be any.
     std::optional<DisplayViewport> internalViewport =
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 16003a2..9abb040 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -19,10 +19,6 @@
         "-DGL_GLEXT_PROTOTYPES",
         "-DEGL_EGLEXT_PROTOTYPES",
     ],
-    include_dirs: [
-        "frameworks/native/vulkan/vkjson",
-        "frameworks/native/vulkan/include",
-    ],
     shared_libs: [
         "android.frameworks.vr.composer@1.0",
         "android.hardware.configstore-utils",
@@ -59,13 +55,11 @@
         "libtimestats_proto",
         "libui",
         "libutils",
-        "libvulkan",
     ],
     static_libs: [
         "librenderengine",
         "libserviceutils",
         "libtrace_proto",
-        "libvkjson",
         "libvr_manager",
         "libvrflinger",
     ],
@@ -132,7 +126,6 @@
         "Effects/Daltonizer.cpp",
         "EventLog/EventLog.cpp",
         "FrameTracker.cpp",
-        "GpuService.cpp",
         "Layer.cpp",
         "LayerBE.cpp",
         "LayerProtoHelper.cpp",
@@ -153,6 +146,7 @@
         "SurfaceInterceptor.cpp",
         "SurfaceTracing.cpp",
         "TimeStats/TimeStats.cpp",
+        "TransactionCompletedThread.cpp",
     ],
 }
 
@@ -190,6 +184,7 @@
         "libhidltransport",
         "liblayers_proto",
         "liblog",
+        "libsync",
         "libtimestats_proto",
         "libutils",
     ],
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 52fbd44..d05ee04 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -229,15 +229,14 @@
             getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
 }
 
-void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
+void BufferLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
+                                  const Rect& viewport, int32_t supportedPerFrameMetadata) {
     // Apply this display's projection's viewport to the visible region
     // before giving it to the HWC HAL.
-    const ui::Transform& tr = display->getTransform();
-    const auto& viewport = display->getViewport();
-    Region visible = tr.transform(visibleRegion.intersect(viewport));
-    const auto displayId = display->getId();
+    Region visible = transform.transform(visibleRegion.intersect(viewport));
+
     if (!hasHwcLayer(displayId)) {
-        ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
+        ALOGE("[%s] failed to setPerFrameData: no HWC layer found for display %" PRIu64,
               mName.string(), displayId);
         return;
     }
@@ -290,7 +289,7 @@
     }
 
     const HdrMetadata& metadata = getDrawingHdrMetadata();
-    error = hwcLayer->setPerFrameMetadata(display->getSupportedPerFrameMetadata(), metadata);
+    error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata, metadata);
     if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
         ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
               to_string(error).c_str(), static_cast<int32_t>(error));
@@ -303,10 +302,10 @@
     }
     getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
     getBE().compositionInfo.hwc.hdrMetadata = getDrawingHdrMetadata();
-    getBE().compositionInfo.hwc.supportedPerFrameMetadata = display->getSupportedPerFrameMetadata();
+    getBE().compositionInfo.hwc.supportedPerFrameMetadata = supportedPerFrameMetadata;
     getBE().compositionInfo.hwc.colorTransform = getColorTransform();
 
-    setHwcLayerBuffer(display);
+    setHwcLayerBuffer(displayId);
 }
 
 bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
@@ -318,10 +317,10 @@
     return hasReadyFrame();
 }
 
-bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+bool BufferLayer::onPostComposition(const std::optional<DisplayId>& displayId,
+                                    const std::shared_ptr<FenceTime>& glDoneFence,
                                     const std::shared_ptr<FenceTime>& presentFence,
                                     const CompositorTiming& compositorTiming) {
-
     // mFrameLatencyNeeded is true when a new frame was latched for the
     // composition.
     if (!mFrameLatencyNeeded) return false;
@@ -352,11 +351,10 @@
     if (presentFence->isValid()) {
         mTimeStats.setPresentFence(layerID, mCurrentFrameNumber, presentFence);
         mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
-    } else if (mFlinger->getHwComposer().isConnected(HWC_DISPLAY_PRIMARY)) {
+    } else if (displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
         // The HWC doesn't support present fences, so use the refresh
         // timestamp instead.
-        const nsecs_t actualPresentTime =
-                mFlinger->getHwComposer().getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+        const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId);
         mTimeStats.setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime);
         mFrameTracker.setActualPresentTime(actualPresentTime);
     }
@@ -522,7 +520,7 @@
 }
 
 bool BufferLayer::hasReadyFrame() const {
-    return hasDrawingBuffer() || getSidebandStreamChanged() || getAutoRefresh();
+    return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
 }
 
 uint32_t BufferLayer::getEffectiveScalingMode() const {
@@ -660,7 +658,7 @@
 }
 
 uint64_t BufferLayer::getHeadFrameNumber() const {
-    if (hasDrawingBuffer()) {
+    if (hasFrameUpdate()) {
         return getFrameNumber();
     } else {
         return mCurrentFrameNumber;
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 1d33a1f..690a4e5 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -80,10 +80,12 @@
 
     bool isHdrY410() const override;
 
-    void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+    void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
+                         int32_t supportedPerFrameMetadata) override;
 
     bool onPreComposition(nsecs_t refreshStartTime) override;
-    bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+    bool onPostComposition(const std::optional<DisplayId>& displayId,
+                           const std::shared_ptr<FenceTime>& glDoneFence,
                            const std::shared_ptr<FenceTime>& presentFence,
                            const CompositorTiming& compositorTiming) override;
 
@@ -134,7 +136,7 @@
 
     virtual std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) = 0;
 
-    virtual bool hasDrawingBuffer() const = 0;
+    virtual bool hasFrameUpdate() const = 0;
 
     virtual void setFilteringEnabled(bool enabled) = 0;
 
@@ -145,7 +147,7 @@
     virtual status_t updateActiveBuffer() = 0;
     virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
 
-    virtual void setHwcLayerBuffer(const sp<const DisplayDevice>& display) = 0;
+    virtual void setHwcLayerBuffer(DisplayId displayId) = 0;
 
     // -----------------------------------------------------------------------
 
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e592a8b..78ab23a 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -23,7 +23,9 @@
 
 BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {}
 
-BufferQueueLayer::~BufferQueueLayer() = default;
+BufferQueueLayer::~BufferQueueLayer() {
+    mConsumer->abandon();
+}
 
 // -----------------------------------------------------------------------
 // Interface implementation for Layer
@@ -33,10 +35,6 @@
     mConsumer->setReleaseFence(releaseFence);
 }
 
-void BufferQueueLayer::abandon() {
-    mConsumer->abandon();
-}
-
 void BufferQueueLayer::setTransformHint(uint32_t orientation) const {
     mConsumer->setTransformHint(orientation);
 }
@@ -84,7 +82,7 @@
         return true;
     }
 
-    if (!hasDrawingBuffer()) {
+    if (!hasFrameUpdate()) {
         return false;
     }
 
@@ -112,7 +110,7 @@
         return true;
     }
 
-    if (!hasDrawingBuffer()) {
+    if (!hasFrameUpdate()) {
         return true;
     }
 
@@ -208,7 +206,7 @@
     return {};
 }
 
-bool BufferQueueLayer::hasDrawingBuffer() const {
+bool BufferQueueLayer::hasFrameUpdate() const {
     return mQueuedFrames > 0;
 }
 
@@ -327,8 +325,7 @@
     return NO_ERROR;
 }
 
-void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
-    const auto displayId = display->getId();
+void BufferQueueLayer::setHwcLayerBuffer(DisplayId displayId) {
     auto& hwcInfo = getBE().mHwcLayers[displayId];
     auto& hwcLayer = hwcInfo.layer;
 
@@ -355,6 +352,11 @@
 void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
     // Add this buffer from our internal queue tracker
     { // Autolock scope
+        // Report the timestamp to the Scheduler.
+        if (mFlinger->mUseScheduler) {
+            mFlinger->mScheduler->addNewFrameTimestamp(item.mTimestamp, item.mIsAutoTimestamp);
+        }
+
         Mutex::Autolock lock(mQueueItemLock);
         // Reset the frame number tracker when we receive the first buffer after
         // a frame number reset
@@ -380,7 +382,17 @@
 
     mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
                                              item.mGraphicBuffer->getHeight(), item.mFrameNumber);
-    mFlinger->signalLayerUpdate();
+    
+    // If this layer is orphaned, then we run a fake vsync pulse so that
+    // dequeueBuffer doesn't block indefinitely.
+    if (isRemovedFromCurrentState()) {
+        bool ignored = false;
+        latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
+        usleep(16000);
+        releasePendingBuffer(systemTime());
+    } else {
+        mFlinger->signalLayerUpdate();
+    }
 }
 
 void BufferQueueLayer::onFrameReplaced(const BufferItem& item) {
@@ -395,7 +407,7 @@
             }
         }
 
-        if (!hasDrawingBuffer()) {
+        if (!hasFrameUpdate()) {
             ALOGE("Can't replace a frame on an empty queue");
             return;
         }
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index abe0bc7..ae0b705 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -40,8 +40,6 @@
 public:
     void onLayerDisplayed(const sp<Fence>& releaseFence) override;
 
-    void abandon() override;
-
     void setTransformHint(uint32_t orientation) const override;
 
     std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
@@ -85,7 +83,7 @@
 
     std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
 
-    bool hasDrawingBuffer() const override;
+    bool hasFrameUpdate() const override;
 
     void setFilteringEnabled(bool enabled) override;
 
@@ -96,8 +94,7 @@
     status_t updateActiveBuffer() override;
     status_t updateFrameNumber(nsecs_t latchTime) override;
 
-    void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
-    // -----------------------------------------------------------------------
+    void setHwcLayerBuffer(DisplayId displayId) override;
 
     // -----------------------------------------------------------------------
     // Interface implementation for BufferLayerConsumer::ContentsChangedListener
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index ac9e783..425f5c7 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -43,9 +43,11 @@
 // -----------------------------------------------------------------------
 // Interface implementation for Layer
 // -----------------------------------------------------------------------
-void BufferStateLayer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {
-    // TODO(marissaw): send the release fence back to buffer owner
-    return;
+void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+    // The transaction completed callback can only be sent if the release fence from the PREVIOUS
+    // frame has fired. In practice, we should never actually wait on the previous release fence
+    // but we should store it just in case.
+    mPreviousReleaseFence = releaseFence;
 }
 
 void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
@@ -54,7 +56,6 @@
 }
 
 void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
-    // TODO(marissaw): use this to signal the buffer owner
     return;
 }
 
@@ -63,7 +64,13 @@
         return true;
     }
 
-    return hasDrawingBuffer();
+    return hasFrameUpdate();
+}
+
+bool BufferStateLayer::willPresentCurrentTransaction() const {
+    // Returns true if the most recent Transaction applied to CurrentState will be presented.
+    return getSidebandStreamChanged() || getAutoRefresh() ||
+            (mCurrentState.modified && mCurrentState.buffer != nullptr);
 }
 
 bool BufferStateLayer::getTransformToDisplayInverse() const {
@@ -83,6 +90,7 @@
     while (!mPendingStates.empty()) {
         popPendingState(stateToCommit);
     }
+    mCurrentStateModified = stateUpdateAvailable && mCurrentState.modified;
     mCurrentState.modified = false;
     return stateUpdateAvailable;
 }
@@ -120,7 +128,11 @@
     return true;
 }
 
-bool BufferStateLayer::setBuffer(sp<GraphicBuffer> buffer) {
+bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer) {
+    if (mCurrentState.buffer) {
+        mReleasePreviousBuffer = true;
+    }
+
     mCurrentState.sequence++;
     mCurrentState.buffer = buffer;
     mCurrentState.modified = true;
@@ -129,6 +141,9 @@
 }
 
 bool BufferStateLayer::setAcquireFence(const sp<Fence>& fence) {
+    // The acquire fences of BufferStateLayers have already signaled before they are set
+    mCallbackHandleAcquireTime = fence->getSignalTime();
+
     mCurrentState.acquireFence = fence;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -184,6 +199,44 @@
     return true;
 }
 
+bool BufferStateLayer::setTransactionCompletedListeners(
+        const std::vector<sp<CallbackHandle>>& handles) {
+    // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return
+    if (handles.empty()) {
+        mReleasePreviousBuffer = false;
+        return false;
+    }
+
+    const bool willPresent = willPresentCurrentTransaction();
+
+    for (const auto& handle : handles) {
+        // If this transaction set a buffer on this layer, release its previous buffer
+        handle->releasePreviousBuffer = mReleasePreviousBuffer;
+
+        // If this layer will be presented in this frame
+        if (willPresent) {
+            // If this transaction set an acquire fence on this layer, set its acquire time
+            handle->acquireTime = mCallbackHandleAcquireTime;
+
+            // Notify the transaction completed thread that there is a pending latched callback
+            // handle
+            mFlinger->getTransactionCompletedThread().registerPendingLatchedCallbackHandle(handle);
+
+            // Store so latched time and release fence can be set
+            mCurrentState.callbackHandles.push_back(handle);
+
+        } else { // If this layer will NOT need to be relatched and presented this frame
+            // Notify the transaction completed thread this handle is done
+            mFlinger->getTransactionCompletedThread().addUnlatchedCallbackHandle(handle);
+        }
+    }
+
+    mReleasePreviousBuffer = false;
+    mCallbackHandleAcquireTime = -1;
+
+    return willPresent;
+}
+
 bool BufferStateLayer::setSize(uint32_t w, uint32_t h) {
     if (mCurrentState.active.w == w && mCurrentState.active.h == h) return false;
     mCurrentState.active.w = w;
@@ -267,7 +320,7 @@
 }
 
 uint32_t BufferStateLayer::getDrawingScalingMode() const {
-    return NATIVE_WINDOW_SCALING_MODE_FREEZE;
+    return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
 }
 
 Region BufferStateLayer::getDrawingSurfaceDamage() const {
@@ -316,8 +369,8 @@
     return {};
 }
 
-bool BufferStateLayer::hasDrawingBuffer() const {
-    return getDrawingState().buffer != nullptr;
+bool BufferStateLayer::hasFrameUpdate() const {
+    return mCurrentStateModified && getCurrentState().buffer != nullptr;
 }
 
 void BufferStateLayer::setFilteringEnabled(bool enabled) {
@@ -405,6 +458,10 @@
         return BAD_VALUE;
     }
 
+    mFlinger->getTransactionCompletedThread()
+            .addLatchedCallbackHandles(getDrawingState().callbackHandles, latchTime,
+                                       mPreviousReleaseFence);
+
     // Handle sync fences
     if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
         // TODO(alecmouri): Fail somewhere upstream if the fence is invalid.
@@ -472,8 +529,7 @@
     }
 
     // TODO(marissaw): properly support mTimeStats
-    mTimeStats.setLayerName(layerID, getName().c_str());
-    mTimeStats.setPostTime(layerID, getFrameNumber(), latchTime);
+    mTimeStats.setPostTime(layerID, getFrameNumber(), getName().c_str(), latchTime);
     mTimeStats.setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
     mTimeStats.setLatchTime(layerID, getFrameNumber(), latchTime);
 
@@ -500,8 +556,7 @@
     return NO_ERROR;
 }
 
-void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
-    const auto displayId = display->getId();
+void BufferStateLayer::setHwcLayerBuffer(DisplayId displayId) {
     auto& hwcInfo = getBE().mHwcLayers[displayId];
     auto& hwcLayer = hwcInfo.layer;
 
@@ -516,6 +571,7 @@
               s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
+    mCurrentStateModified = false;
     mFrameNumber++;
 }
 
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 0c6eaf5..315d5af 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -62,13 +62,14 @@
     bool setTransform(uint32_t transform) override;
     bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
     bool setCrop(const Rect& crop) override;
-    bool setBuffer(sp<GraphicBuffer> buffer) override;
+    bool setBuffer(const sp<GraphicBuffer>& buffer) override;
     bool setAcquireFence(const sp<Fence>& fence) override;
     bool setDataspace(ui::Dataspace dataspace) override;
     bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
     bool setSurfaceDamageRegion(const Region& surfaceDamage) override;
     bool setApi(int32_t api) override;
     bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
+    bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
 
     bool setSize(uint32_t w, uint32_t h) override;
     bool setPosition(float x, float y, bool immediate) override;
@@ -110,7 +111,7 @@
 
     std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
 
-    bool hasDrawingBuffer() const override;
+    bool hasFrameUpdate() const override;
 
     void setFilteringEnabled(bool enabled) override;
 
@@ -121,10 +122,11 @@
     status_t updateActiveBuffer() override;
     status_t updateFrameNumber(nsecs_t latchTime) override;
 
-    void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
-    // -----------------------------------------------------------------------
+    void setHwcLayerBuffer(DisplayId displayId) override;
+
 private:
     void onFirstRef() override;
+    bool willPresentCurrentTransaction() const;
 
     static const std::array<float, 16> IDENTITY_MATRIX;
 
@@ -136,6 +138,12 @@
 
     uint32_t mFrameNumber{0};
 
+    sp<Fence> mPreviousReleaseFence;
+
+    bool mCurrentStateModified = false;
+    bool mReleasePreviousBuffer = false;
+    nsecs_t mCallbackHandleAcquireTime = -1;
+
     // TODO(marissaw): support sticky transform for LEGACY camera mode
 };
 
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 263f872..ad716ef 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -57,13 +57,12 @@
     return !isHiddenByPolicy() && getAlpha() > 0.0f;
 }
 
-void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
-    const ui::Transform& tr = display->getTransform();
-    const auto& viewport = display->getViewport();
-    Region visible = tr.transform(visibleRegion.intersect(viewport));
-    const auto displayId = display->getId();
+void ColorLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
+                                 const Rect& viewport, int32_t /* supportedPerFrameMetadata */) {
+    Region visible = transform.transform(visibleRegion.intersect(viewport));
+
     if (!hasHwcLayer(displayId)) {
-        ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
+        ALOGE("[%s] failed to setPerFrameData: no HWC layer found for display %" PRIu64,
               mName.string(), displayId);
         return;
     }
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 2c10357..d1b1697 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -33,7 +33,10 @@
                         bool useIdentityTransform);
     bool isVisible() const override;
 
-    void setPerFrameData(const sp<const DisplayDevice>& display) override;
+    void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
+                         int32_t supportedPerFrameMetadata) override;
+
+    bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
 
 protected:
     FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 44e843e..ca49f6c 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -32,6 +32,6 @@
     return !isHiddenByPolicy();
 }
 
-void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&) {}
+void ContainerLayer::setPerFrameData(DisplayId, const ui::Transform&, const Rect&, int32_t) {}
 
 } // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 8eddc7f..413844b 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -33,9 +33,12 @@
                 bool useIdentityTransform) override;
     bool isVisible() const override;
 
-    void setPerFrameData(const sp<const DisplayDevice>& display) override;
+    void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
+                         int32_t supportedPerFrameMetadata) override;
 
     bool isCreatedFromMainThread() const override { return true; }
+
+    bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 6f645df..f51daf3 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -28,12 +28,15 @@
 #include <string.h>
 #include <math.h>
 
+#include <android-base/stringprintf.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
 #include <cutils/properties.h>
 #include <gui/Surface.h>
 #include <hardware/gralloc.h>
 #include <renderengine/RenderEngine.h>
+#include <sync/sync.h>
+#include <system/window.h>
 #include <ui/DebugUtils.h>
 #include <ui/DisplayInfo.h>
 #include <ui/PixelFormat.h>
@@ -211,22 +214,20 @@
 
 DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
                                                      const wp<IBinder>& displayToken,
-                                                     DisplayDevice::DisplayType type, int32_t id)
-      : flinger(flinger), displayToken(displayToken), type(type), id(id) {}
+                                                     const std::optional<DisplayId>& displayId)
+      : flinger(flinger), displayToken(displayToken), displayId(displayId) {}
 
 DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args)
       : lastCompositionHadVisibleLayers(false),
         mFlinger(args.flinger),
-        mType(args.type),
-        mId(args.id),
         mDisplayToken(args.displayToken),
+        mId(args.displayId),
         mNativeWindow(args.nativeWindow),
+        mGraphicBuffer(nullptr),
         mDisplaySurface(args.displaySurface),
-        mSurface{std::move(args.renderSurface)},
-        mDisplayWidth(args.displayWidth),
-        mDisplayHeight(args.displayHeight),
         mDisplayInstallOrientation(args.displayInstallOrientation),
         mPageFlipCount(0),
+        mIsVirtual(args.isVirtual),
         mIsSecure(args.isSecure),
         mLayerStack(NO_LAYER_STACK),
         mOrientation(),
@@ -239,14 +240,12 @@
         mHasHdr10(false),
         mHasHLG(false),
         mHasDolbyVision(false),
-        mSupportedPerFrameMetadata(args.supportedPerFrameMetadata) {
+        mSupportedPerFrameMetadata(args.supportedPerFrameMetadata),
+        mIsPrimary(args.isPrimary) {
     populateColorModes(args.hwcColorModes);
 
     ALOGE_IF(!mNativeWindow, "No native window was set for display");
     ALOGE_IF(!mDisplaySurface, "No display surface was set for display");
-    ALOGE_IF(!mSurface, "No render surface was set for display");
-    ALOGE_IF(mDisplayWidth <= 0 || mDisplayHeight <= 0,
-             "Invalid dimensions of %d x %d were set for display", mDisplayWidth, mDisplayHeight);
 
     std::vector<Hdr> types = args.hdrCapabilities.getSupportedHdrTypes();
     for (Hdr hdrType : types) {
@@ -285,6 +284,14 @@
     }
     mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
 
+    ANativeWindow* const window = mNativeWindow.get();
+
+    int status = native_window_api_connect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
+    ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
+
+    mDisplayWidth = ANativeWindow_getWidth(window);
+    mDisplayHeight = ANativeWindow_getHeight(window);
+
     // initialize the display orientation transform.
     setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
 }
@@ -292,16 +299,12 @@
 DisplayDevice::~DisplayDevice() = default;
 
 void DisplayDevice::disconnect(HWComposer& hwc) {
-    if (mId >= 0) {
-        hwc.disconnectDisplay(mId);
-        mId = -1;
+    if (mId) {
+        hwc.disconnectDisplay(*mId);
+        mId.reset();
     }
 }
 
-bool DisplayDevice::isValid() const {
-    return mFlinger != nullptr;
-}
-
 int DisplayDevice::getWidth() const {
     return mDisplayWidth;
 }
@@ -323,7 +326,6 @@
 
 void DisplayDevice::flip() const
 {
-    mFlinger->getRenderEngine().checkErrors();
     mPageFlipCount++;
 }
 
@@ -333,9 +335,11 @@
 
 status_t DisplayDevice::prepareFrame(HWComposer& hwc,
         std::vector<CompositionInfo>& compositionData) {
-    status_t error = hwc.prepare(*this, compositionData);
-    if (error != NO_ERROR) {
-        return error;
+    if (mId) {
+        status_t error = hwc.prepare(*mId, compositionData);
+        if (error != NO_ERROR) {
+            return error;
+        }
     }
 
     DisplaySurface::CompositionType compositionType;
@@ -356,9 +360,71 @@
     return mDisplaySurface->prepareFrame(compositionType);
 }
 
-void DisplayDevice::swapBuffers(HWComposer& hwc) const {
+sp<GraphicBuffer> DisplayDevice::dequeueBuffer() {
+    int fd;
+    ANativeWindowBuffer* buffer;
+
+    status_t res = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd);
+
+    if (res != NO_ERROR) {
+        ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d",
+              getDisplayName().c_str(), res);
+        // Return fast here as we can't do much more - any rendering we do
+        // now will just be wrong.
+        return mGraphicBuffer;
+    }
+
+    ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
+             mGraphicBuffer->getNativeBuffer()->handle);
+    mGraphicBuffer = GraphicBuffer::from(buffer);
+
+    // Block until the buffer is ready
+    // TODO(alecmouri): it's perhaps more appropriate to block renderengine so
+    // that the gl driver can block instead.
+    if (fd >= 0) {
+        sync_wait(fd, -1);
+        close(fd);
+    }
+
+    return mGraphicBuffer;
+}
+
+void DisplayDevice::queueBuffer(HWComposer& hwc) {
     if (hwc.hasClientComposition(mId) || hwc.hasFlipClientTargetRequest(mId)) {
-        mSurface->swapBuffers();
+        // hasFlipClientTargetRequest could return true even if we haven't
+        // dequeued a buffer before. Try dequeueing one if we don't have a
+        // buffer ready.
+        if (mGraphicBuffer == nullptr) {
+            ALOGI("Attempting to queue a client composited buffer without one "
+                  "previously dequeued for display [%s]. Attempting to dequeue "
+                  "a scratch buffer now",
+                  mDisplayName.c_str());
+            // We shouldn't deadlock here, since mGraphicBuffer == nullptr only
+            // after a successful call to queueBuffer, or if dequeueBuffer has
+            // never been called.
+            dequeueBuffer();
+        }
+
+        if (mGraphicBuffer == nullptr) {
+            ALOGE("No buffer is ready for display [%s]", mDisplayName.c_str());
+        } else {
+            int fd = mBufferReady.release();
+
+            status_t res = mNativeWindow->queueBuffer(mNativeWindow.get(),
+                                                      mGraphicBuffer->getNativeBuffer(), fd);
+            if (res != NO_ERROR) {
+                ALOGE("Error when queueing buffer for display [%s]: %d", mDisplayName.c_str(), res);
+                // We risk blocking on dequeueBuffer if the primary display failed
+                // to queue up its buffer, so crash here.
+                if (isPrimary()) {
+                    LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", res);
+                } else {
+                    mNativeWindow->cancelBuffer(mNativeWindow.get(),
+                                                mGraphicBuffer->getNativeBuffer(), fd);
+                }
+            }
+            mGraphicBuffer = nullptr;
+        }
     }
 
     status_t result = mDisplaySurface->advanceFrame();
@@ -367,16 +433,10 @@
     }
 }
 
-void DisplayDevice::onSwapBuffersCompleted() const {
+void DisplayDevice::onPresentDisplayCompleted() {
     mDisplaySurface->onFrameCommitted();
 }
 
-bool DisplayDevice::makeCurrent() const {
-    bool success = mFlinger->getRenderEngine().setCurrentSurface(*mSurface);
-    setViewportAndProjection();
-    return success;
-}
-
 void DisplayDevice::setViewportAndProjection() const {
     size_t w = mDisplayWidth;
     size_t h = mDisplayHeight;
@@ -384,6 +444,13 @@
     mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, ui::Transform::ROT_0);
 }
 
+void DisplayDevice::finishBuffer() {
+    mBufferReady = mFlinger->getRenderEngine().flush();
+    if (mBufferReady.get() < 0) {
+        mFlinger->getRenderEngine().finish();
+    }
+}
+
 const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
     return mDisplaySurface->getClientTargetAcquireFence();
 }
@@ -532,19 +599,10 @@
 void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
     dirtyRegion.set(getBounds());
 
-    mSurface->setNativeWindow(nullptr);
-
     mDisplaySurface->resizeBuffers(newWidth, newHeight);
 
-    ANativeWindow* const window = mNativeWindow.get();
-    mSurface->setNativeWindow(window);
-    mDisplayWidth = mSurface->getWidth();
-    mDisplayHeight = mSurface->getHeight();
-
-    LOG_FATAL_IF(mDisplayWidth != newWidth,
-                "Unable to set new width to %d", newWidth);
-    LOG_FATAL_IF(mDisplayHeight != newHeight,
-                "Unable to set new height to %d", newHeight);
+    mDisplayWidth = newWidth;
+    mDisplayHeight = newHeight;
 }
 
 void DisplayDevice::setProjection(int orientation,
@@ -599,7 +657,7 @@
 
     // need to take care of primary display rotation for mGlobalTransform
     // for case if the panel is not installed aligned with device orientation
-    if (mType == DisplayType::DISPLAY_PRIMARY) {
+    if (isPrimary()) {
         DisplayDevice::orientationToTransfrom(
                 (orientation + mDisplayInstallOrientation) % (DisplayState::eOrientation270 + 1),
                 w, h, &R);
@@ -646,17 +704,23 @@
     return sPrimaryDisplayOrientation;
 }
 
+std::string DisplayDevice::getDebugName() const {
+    const auto id = mId ? base::StringPrintf("%" PRIu64 ", ", *mId) : std::string();
+    return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(),
+                              isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "",
+                              mDisplayName.c_str());
+}
+
 void DisplayDevice::dump(String8& result) const {
     const ui::Transform& tr(mGlobalTransform);
     ANativeWindow* const window = mNativeWindow.get();
-    result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.c_str());
-    result.appendFormat("   type=%x, ID=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
-                        "(%d:%d:%d:%d), orient=%2d (type=%08x), "
-                        "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
-                        mType, mId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
-                        mSurface->queryRedSize(), mSurface->queryGreenSize(),
-                        mSurface->queryBlueSize(), mSurface->queryAlphaSize(), mOrientation,
-                        tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
+    result.appendFormat("+ %s\n", getDebugName().c_str());
+    result.appendFormat("  layerStack=%u, (%4dx%4d), ANativeWindow=%p "
+                        "format=%d, orient=%2d (type=%08x), flips=%u, isSecure=%d, "
+                        "powerMode=%d, activeConfig=%d, numLayers=%zu\n",
+                        mLayerStack, mDisplayWidth, mDisplayHeight, window,
+                        ANativeWindow_getFormat(window), mOrientation, tr.getType(),
+                        getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
                         mVisibleLayersSortedByZ.size());
     result.appendFormat("   v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
                         "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
@@ -667,9 +731,9 @@
     auto const surface = static_cast<Surface*>(window);
     ui::Dataspace dataspace = surface->getBuffersDataSpace();
     result.appendFormat("   wideColorGamut=%d, hdr10=%d, colorMode=%s, dataspace: %s (%d)\n",
-                        mHasWideColorGamut, mHasHdr10,
-                        decodeColorMode(mActiveColorMode).c_str(),
-                        dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
+                        mHasWideColorGamut, mHasHdr10, decodeColorMode(mActiveColorMode).c_str(),
+                        dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(),
+                        dataspace);
 
     String8 surfaceDump;
     mDisplaySurface->dumpAsString(surfaceDump);
@@ -693,7 +757,7 @@
     const Dataspace dataspace = colorModeToDataspace(mode);
     const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
 
-    ALOGV("DisplayDevice %d/%d: map (%s, %s) to (%s, %s, %s)", mType, mId,
+    ALOGV("%s: map (%s, %s) to (%s, %s, %s)", getDebugName().c_str(),
           dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
           decodeRenderIntent(intent).c_str(),
           dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 38482c9..eb2c5c3 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -20,27 +20,29 @@
 #include <stdlib.h>
 
 #include <memory>
+#include <optional>
 #include <string>
 #include <unordered_map>
 
+#include <android/native_window.h>
 #include <binder/IBinder.h>
 #include <gui/LayerState.h>
 #include <hardware/hwcomposer_defs.h>
 #include <math/mat4.h>
-#include <renderengine/Surface.h>
+#include <renderengine/RenderEngine.h>
+#include <system/window.h>
 #include <ui/GraphicTypes.h>
 #include <ui/HdrCapabilities.h>
 #include <ui/Region.h>
 #include <ui/Transform.h>
-#include <utils/RefBase.h>
 #include <utils/Mutex.h>
+#include <utils/RefBase.h>
 #include <utils/String8.h>
 #include <utils/Timers.h>
 
+#include "DisplayHardware/DisplayIdentification.h"
 #include "RenderArea.h"
 
-struct ANativeWindow;
-
 namespace android {
 
 class DisplaySurface;
@@ -66,25 +68,15 @@
     Region undefinedRegion;
     bool lastCompositionHadVisibleLayers;
 
-    enum DisplayType {
-        DISPLAY_ID_INVALID = -1,
-        DISPLAY_PRIMARY     = HWC_DISPLAY_PRIMARY,
-        DISPLAY_EXTERNAL    = HWC_DISPLAY_EXTERNAL,
-        DISPLAY_VIRTUAL     = HWC_DISPLAY_VIRTUAL,
-        NUM_BUILTIN_DISPLAY_TYPES = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
-    };
-
     enum {
         NO_LAYER_STACK = 0xFFFFFFFF,
     };
 
     explicit DisplayDevice(DisplayDeviceCreationArgs&& args);
-
     ~DisplayDevice();
 
-    // whether this is a valid object. An invalid DisplayDevice is returned
-    // when an non existing id is requested
-    bool isValid() const;
+    bool isVirtual() const { return mIsVirtual; }
+    bool isPrimary() const { return mIsPrimary; }
 
     // isSecure indicates whether this display can be trusted to display
     // secure surfaces.
@@ -118,11 +110,9 @@
     bool                    needsFiltering() const { return mNeedsFiltering; }
 
     uint32_t                getLayerStack() const { return mLayerStack; }
-    int32_t                 getDisplayType() const { return mType; }
-    bool                    isPrimary() const { return mType == DISPLAY_PRIMARY; }
-    bool                    isVirtual() const { return mType == DISPLAY_VIRTUAL; }
-    int32_t                 getId() const { return mId; }
-    const wp<IBinder>&      getDisplayToken() const { return mDisplayToken; }
+
+    const std::optional<DisplayId>& getId() const { return mId; }
+    const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
 
     int32_t getSupportedPerFrameMetadata() const { return mSupportedPerFrameMetadata; }
 
@@ -156,10 +146,13 @@
                           ui::Dataspace* outDataspace, ui::ColorMode* outMode,
                           ui::RenderIntent* outIntent) const;
 
-    void swapBuffers(HWComposer& hwc) const;
+    // Queues the drawn buffer for consumption by HWC.
+    void queueBuffer(HWComposer& hwc);
+    // Allocates a buffer as scratch space for GPU composition
+    sp<GraphicBuffer> dequeueBuffer();
 
     // called after h/w composer has completed its set() call
-    void onSwapBuffersCompleted() const;
+    void onPresentDisplayCompleted();
 
     Rect getBounds() const {
         return Rect(mDisplayWidth, mDisplayHeight);
@@ -169,7 +162,11 @@
     void setDisplayName(const std::string& displayName);
     const std::string& getDisplayName() const { return mDisplayName; }
 
-    bool makeCurrent() const;
+    // Acquires a new buffer for GPU composition.
+    void readyNewBuffer();
+    // Marks the current buffer has finished, so that it can be presented and
+    // swapped out.
+    void finishBuffer();
     void setViewportAndProjection() const;
 
     const sp<Fence>& getClientTargetAcquireFence() const;
@@ -203,28 +200,32 @@
      * Debugging
      */
     uint32_t getPageFlipCount() const;
+    std::string getDebugName() const;
     void dump(String8& result) const;
 
 private:
-    /*
-     *  Constants, set during initialization
-     */
-    sp<SurfaceFlinger> mFlinger;
-    DisplayType mType;
-    int32_t mId;
-    wp<IBinder> mDisplayToken;
+    const sp<SurfaceFlinger> mFlinger;
+    const wp<IBinder> mDisplayToken;
+
+    std::optional<DisplayId> mId;
 
     // ANativeWindow this display is rendering into
     sp<ANativeWindow> mNativeWindow;
+    // Current buffer that this display can render to.
+    sp<GraphicBuffer> mGraphicBuffer;
     sp<DisplaySurface> mDisplaySurface;
+    // File descriptor indicating that mGraphicBuffer is ready for display, i.e.
+    // that drawing to the buffer is now complete.
+    base::unique_fd mBufferReady;
 
-    std::unique_ptr<renderengine::Surface> mSurface;
     int             mDisplayWidth;
     int             mDisplayHeight;
     const int       mDisplayInstallOrientation;
     mutable uint32_t mPageFlipCount;
     std::string     mDisplayName;
-    bool            mIsSecure;
+
+    const bool mIsVirtual;
+    const bool mIsSecure;
 
     /*
      * Can only accessed from the main thread, these members
@@ -298,13 +299,16 @@
             const ui::ColorMode mode, const ui::RenderIntent intent);
 
     std::unordered_map<ColorModeKey, ColorModeValue> mColorModes;
+
+    // TODO(b/74619554): Remove special cases for primary display.
+    const bool mIsPrimary;
 };
 
 struct DisplayDeviceState {
-    bool isVirtual() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
+    bool isVirtual() const { return !displayId.has_value(); }
 
     int32_t sequenceId = sNextSequenceId++;
-    DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_ID_INVALID;
+    std::optional<DisplayId> displayId;
     sp<IGraphicBufferProducer> surface;
     uint32_t layerStack = DisplayDevice::NO_LAYER_STACK;
     Rect viewport;
@@ -323,25 +327,23 @@
     // We use a constructor to ensure some of the values are set, without
     // assuming a default value.
     DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger, const wp<IBinder>& displayToken,
-                              DisplayDevice::DisplayType type, int32_t id);
+                              const std::optional<DisplayId>& displayId);
 
     const sp<SurfaceFlinger> flinger;
     const wp<IBinder> displayToken;
-    const DisplayDevice::DisplayType type;
-    const int32_t id;
+    const std::optional<DisplayId> displayId;
 
+    bool isVirtual{false};
     bool isSecure{false};
     sp<ANativeWindow> nativeWindow;
     sp<DisplaySurface> displaySurface;
-    std::unique_ptr<renderengine::Surface> renderSurface;
-    int displayWidth{0};
-    int displayHeight{0};
     int displayInstallOrientation{DisplayState::eOrientationDefault};
     bool hasWideColorGamut{false};
     HdrCapabilities hdrCapabilities;
     int32_t supportedPerFrameMetadata{0};
     std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
     int initialPowerMode{HWC_POWER_MODE_NORMAL};
+    bool isPrimary{false};
 };
 
 class DisplayRenderArea : public RenderArea {
@@ -349,10 +351,11 @@
     DisplayRenderArea(const sp<const DisplayDevice> device,
                       ui::Transform::orientation_flags rotation = ui::Transform::ROT_0)
           : DisplayRenderArea(device, device->getBounds(), device->getWidth(), device->getHeight(),
-                              rotation) {}
+                              device->getCompositionDataSpace(), rotation) {}
     DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqWidth,
-                      uint32_t reqHeight, ui::Transform::orientation_flags rotation)
-          : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE,
+                      uint32_t reqHeight, ui::Dataspace reqDataSpace,
+                      ui::Transform::orientation_flags rotation)
+          : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace,
                        getDisplayRotation(rotation, device->getInstallOrientation())),
             mDevice(device),
             mSourceCrop(sourceCrop) {}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index dcc4138..ec240f3 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -33,6 +33,9 @@
 
 constexpr size_t kEdidHeaderLength = 5;
 
+constexpr uint16_t kFallbackEdidManufacturerId = 0;
+constexpr uint16_t kVirtualEdidManufacturerId = 0xffffu;
+
 std::optional<uint8_t> getEdidDescriptorType(const byte_view& view) {
     if (view.size() < kEdidHeaderLength || view[0] || view[1] || view[2] || view[4]) {
         return {};
@@ -165,7 +168,8 @@
     return a && b && c ? std::make_optional(PnpId{a, b, c}) : std::nullopt;
 }
 
-std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData& data) {
+std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData(
+        uint8_t port, const DisplayIdentificationData& data) {
     if (!isEdid(data)) {
         ALOGE("Display identification data has unknown format.");
         return {};
@@ -179,7 +183,16 @@
     // Hash display name instead of using product code or serial number, since the latter have been
     // observed to change on some displays with multiple inputs.
     const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName));
-    return getEdidDisplayId(port, edid->manufacturerId, hash);
+    return DisplayIdentificationInfo{getEdidDisplayId(port, edid->manufacturerId, hash),
+                                     std::string(edid->displayName)};
+}
+
+DisplayId getFallbackDisplayId(uint8_t port) {
+    return getEdidDisplayId(port, kFallbackEdidManufacturerId, 0);
+}
+
+DisplayId getVirtualDisplayId(uint32_t id) {
+    return getEdidDisplayId(0, kVirtualEdidManufacturerId, id);
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index 379f2d3..1f2e789 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -19,6 +19,7 @@
 #include <array>
 #include <cstdint>
 #include <optional>
+#include <string>
 #include <string_view>
 #include <vector>
 
@@ -27,6 +28,11 @@
 using DisplayId = uint64_t;
 using DisplayIdentificationData = std::vector<uint8_t>;
 
+struct DisplayIdentificationInfo {
+    DisplayId id;
+    std::string name;
+};
+
 // NUL-terminated plug and play ID.
 using PnpId = std::array<char, 4>;
 
@@ -40,6 +46,10 @@
 std::optional<Edid> parseEdid(const DisplayIdentificationData&);
 std::optional<PnpId> getPnpId(uint16_t manufacturerId);
 
-std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData&);
+std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData(
+        uint8_t port, const DisplayIdentificationData&);
+
+DisplayId getFallbackDisplayId(uint8_t port);
+DisplayId getVirtualDisplayId(uint32_t id);
 
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index e6d7834..f3f8d9d 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -52,26 +52,25 @@
  *
  */
 
-FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp,
-        const sp<IGraphicBufferConsumer>& consumer) :
-    ConsumerBase(consumer),
-    mDisplayType(disp),
-    mCurrentBufferSlot(-1),
-    mCurrentBuffer(),
-    mCurrentFence(Fence::NO_FENCE),
-    mHwc(hwc),
-    mHasPendingRelease(false),
-    mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
-    mPreviousBuffer()
-{
-    ALOGV("Creating for display %d", disp);
+FramebufferSurface::FramebufferSurface(HWComposer& hwc, DisplayId displayId,
+                                       const sp<IGraphicBufferConsumer>& consumer)
+      : ConsumerBase(consumer),
+        mDisplayId(displayId),
+        mCurrentBufferSlot(-1),
+        mCurrentBuffer(),
+        mCurrentFence(Fence::NO_FENCE),
+        mHwc(hwc),
+        mHasPendingRelease(false),
+        mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
+        mPreviousBuffer() {
+    ALOGV("Creating for display %" PRIu64, displayId);
 
     mName = "FramebufferSurface";
     mConsumer->setConsumerName(mName);
     mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
                                        GRALLOC_USAGE_HW_RENDER |
                                        GRALLOC_USAGE_HW_COMPOSER);
-    const auto& activeConfig = mHwc.getActiveConfig(disp);
+    const auto& activeConfig = mHwc.getActiveConfig(displayId);
     mConsumer->setDefaultBufferSize(activeConfig->getWidth(),
             activeConfig->getHeight());
     mConsumer->setMaxAcquiredBufferCount(
@@ -142,8 +141,7 @@
     mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
             &outSlot, &outBuffer);
     outDataspace = static_cast<Dataspace>(item.mDataSpace);
-    status_t result =
-            mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
+    status_t result = mHwc.setClientTarget(mDisplayId, outSlot, outFence, outBuffer, outDataspace);
     if (result != NO_ERROR) {
         ALOGE("error posting framebuffer: %d", result);
         return result;
@@ -161,7 +159,7 @@
 
 void FramebufferSurface::onFrameCommitted() {
     if (mHasPendingRelease) {
-        sp<Fence> fence = mHwc.getPresentFence(mDisplayType);
+        sp<Fence> fence = mHwc.getPresentFence(mDisplayId);
         if (fence->isValid()) {
             status_t result = addReleaseFence(mPreviousBufferSlot,
                     mPreviousBuffer, fence);
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 0fd8e9e..2431dfd 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H
 #define ANDROID_SF_FRAMEBUFFER_SURFACE_H
 
+#include "DisplayIdentification.h"
 #include "DisplaySurface.h"
 #include "HWComposerBufferCache.h"
 
@@ -38,7 +39,8 @@
 class FramebufferSurface : public ConsumerBase,
                            public DisplaySurface {
 public:
-    FramebufferSurface(HWComposer& hwc, int disp, const sp<IGraphicBufferConsumer>& consumer);
+    FramebufferSurface(HWComposer& hwc, DisplayId displayId,
+                       const sp<IGraphicBufferConsumer>& consumer);
 
     virtual status_t beginFrame(bool mustRecompose);
     virtual status_t prepareFrame(CompositionType compositionType);
@@ -63,8 +65,7 @@
     status_t nextBuffer(uint32_t& outSlot, sp<GraphicBuffer>& outBuffer,
             sp<Fence>& outFence, ui::Dataspace& outDataspace);
 
-    // mDisplayType must match one of the HWC display types
-    int mDisplayType;
+    const DisplayId mDisplayId;
 
     // mCurrentBufferIndex is the slot index of the current buffer or
     // INVALID_BUFFER_SLOT to indicate that either there is no current buffer
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 3a40648..393041d 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -184,7 +184,6 @@
 
         auto newDisplay = std::make_unique<Display>(
                 *mComposer.get(), mPowerAdvisor, mCapabilities, displayId, displayType);
-        newDisplay->setFrequencyScaleParameters(mFrequencyScaler);
         newDisplay->setConnected(true);
         mDisplays.emplace(displayId, std::move(newDisplay));
     } else if (connection == Connection::Disconnected) {
@@ -224,14 +223,6 @@
     return static_cast<Error>(mComposer->executeCommands());
 }
 
-void Device::setDisplayFrequencyScaleParameters(Device::FrequencyScaler frequencyScaler) {
-    mFrequencyScaler = frequencyScaler;
-}
-
-Device::FrequencyScaler Device::getDisplayFrequencyScaleParameters() {
-    return mFrequencyScaler;
-}
-
 // Display methods
 
 Display::Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
@@ -271,7 +262,6 @@
     mWidth(-1),
     mHeight(-1),
     mVsyncPeriod(-1),
-    mFrequencyScaler(display.mFrequencyScaler),
     mDpiX(-1),
     mDpiY(-1) {}
 
@@ -711,10 +701,6 @@
     mIsConnected = connected;
 }
 
-void Display::setFrequencyScaleParameters(Device::FrequencyScaler frequencyScaler) {
-    mFrequencyScaler = frequencyScaler;
-}
-
 int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute)
 {
     int32_t value = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 363adb5..d274631 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -23,7 +23,6 @@
 #undef HWC2_INCLUDE_STRINGIFICATION
 #undef HWC2_USE_CPP11
 
-#include <cutils/properties.h>
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
 #include <ui/GraphicTypes.h>
@@ -85,11 +84,6 @@
 public:
     explicit Device(std::unique_ptr<android::Hwc2::Composer> composer);
 
-    struct FrequencyScaler {
-        int32_t multiplier = 1;
-        int32_t divisor = 1;
-    };
-
     void registerCallback(ComposerCallback* callback, int32_t sequenceId);
 
     // Required by HWC2
@@ -121,9 +115,6 @@
     // This method provides an explicit way to flush state changes to HWC.
     Error flushCommands();
 
-    void setDisplayFrequencyScaleParameters(FrequencyScaler frequecyScaler);
-    FrequencyScaler getDisplayFrequencyScaleParameters();
-
 private:
     // Initialization methods
 
@@ -134,7 +125,6 @@
     std::unordered_set<Capability> mCapabilities;
     std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays;
     android::Hwc2::impl::PowerAdvisor mPowerAdvisor;
-    FrequencyScaler mFrequencyScaler;
     bool mRegisteredCallback = false;
 };
 
@@ -199,8 +189,7 @@
 
         int32_t getWidth() const { return mWidth; }
         int32_t getHeight() const { return mHeight; }
-        nsecs_t getVsyncPeriod() const {
-            return mVsyncPeriod * mFrequencyScaler.multiplier / mFrequencyScaler.divisor; }
+        nsecs_t getVsyncPeriod() const { return mVsyncPeriod; }
         float getDpiX() const { return mDpiX; }
         float getDpiY() const { return mDpiY; }
 
@@ -213,7 +202,6 @@
         int32_t mWidth;
         int32_t mHeight;
         nsecs_t mVsyncPeriod;
-        Device::FrequencyScaler mFrequencyScaler;
         float mDpiX;
         float mDpiY;
     };
@@ -281,7 +269,6 @@
     hwc2_display_t getId() const { return mId; }
     bool isConnected() const { return mIsConnected; }
     void setConnected(bool connected);  // For use by Device only
-    void setFrequencyScaleParameters(Device::FrequencyScaler frequencyScaler);
 
 private:
     int32_t getAttribute(hwc2_config_t configId, Attribute attribute);
@@ -306,7 +293,6 @@
     hwc2_display_t mId;
     bool mIsConnected;
     DisplayType mType;
-    Device::FrequencyScaler mFrequencyScaler;
     std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
     std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
 };
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 6b56ca4..4c472b8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -58,15 +58,15 @@
     ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg)
 
 #define LOG_DISPLAY_ERROR(displayId, msg) \
-    ALOGE("%s failed for display %d: %s", __FUNCTION__, displayId, msg)
+    ALOGE("%s failed for display %" PRIu64 ": %s", __FUNCTION__, displayId, msg)
 
-#define LOG_HWC_ERROR(what, error, displayId)                                     \
-    ALOGE("%s: %s failed for display %d: %s (%d)", __FUNCTION__, what, displayId, \
+#define LOG_HWC_ERROR(what, error, displayId)                                              \
+    ALOGE("%s: %s failed for display %" PRIu64 ": %s (%d)", __FUNCTION__, what, displayId, \
           to_string(error).c_str(), static_cast<int32_t>(error))
 
 #define RETURN_IF_INVALID_DISPLAY(displayId, ...)            \
     do {                                                     \
-        if (!isValidDisplay(displayId)) {                    \
+        if (mDisplayData.count(displayId) == 0) {            \
             LOG_DISPLAY_ERROR(displayId, "Invalid display"); \
             return __VA_ARGS__;                              \
         }                                                    \
@@ -92,7 +92,9 @@
 HWComposer::HWComposer(std::unique_ptr<android::Hwc2::Composer> composer)
       : mHwcDevice(std::make_unique<HWC2::Device>(std::move(composer))) {}
 
-HWComposer::~HWComposer() = default;
+HWComposer::~HWComposer() {
+    mDisplayData.clear();
+}
 
 void HWComposer::registerCallback(HWC2::ComposerCallback* callback,
                                   int32_t sequenceId) {
@@ -116,11 +118,6 @@
     return mHwcDevice->getCapabilities().count(capability) > 0;
 }
 
-bool HWComposer::isValidDisplay(int32_t displayId) const {
-    return static_cast<size_t>(displayId) < mDisplayData.size() &&
-            mDisplayData[displayId].hwcDisplay;
-}
-
 void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) {
     bool valid = true;
     switch (from) {
@@ -146,52 +143,50 @@
     }
 }
 
-std::optional<DisplayId> HWComposer::onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
-                                               HWC2::Connection connection) {
-    if (displayType >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
-        ALOGE("Invalid display type of %d", displayType);
-        return {};
-    }
+std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId,
+                                                               HWC2::Connection connection) {
+    std::optional<DisplayIdentificationInfo> info;
 
-    ALOGV("hotplug: %" PRIu64 ", %s %s", hwcDisplayId,
-          displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
-          to_string(connection).c_str());
-    mHwcDevice->onHotplug(hwcDisplayId, connection);
-
-    std::optional<DisplayId> displayId;
-
-    if (connection == HWC2::Connection::Connected) {
-        uint8_t port;
-        DisplayIdentificationData data;
-        if (getDisplayIdentificationData(hwcDisplayId, &port, &data)) {
-            displayId = generateDisplayId(port, data);
-            ALOGE_IF(!displayId, "Failed to generate stable ID for display %" PRIu64, hwcDisplayId);
+    if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) {
+        info = DisplayIdentificationInfo{*displayId, std::string()};
+    } else {
+        if (connection == HWC2::Connection::Disconnected) {
+            ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId);
+            return {};
         }
+
+        info = onHotplugConnect(hwcDisplayId);
+        if (!info) return {};
     }
 
+    ALOGV("%s: %s %s display %" PRIu64 " with HWC ID %" PRIu64, __FUNCTION__,
+          to_string(connection).c_str(),
+          hwcDisplayId == mInternalHwcDisplayId ? "internal" : "external", info->id, hwcDisplayId);
+
+    mHwcDevice->onHotplug(hwcDisplayId, connection);
+
     // Disconnect is handled through HWComposer::disconnectDisplay via
     // SurfaceFlinger's onHotplugReceived callback handling
     if (connection == HWC2::Connection::Connected) {
-        mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(hwcDisplayId);
-        mHwcDisplaySlots[hwcDisplayId] = displayType;
+        mDisplayData[info->id].hwcDisplay = mHwcDevice->getDisplayById(hwcDisplayId);
+        mPhysicalDisplayIdMap[hwcDisplayId] = info->id;
     }
 
-    return displayId;
+    return info;
 }
 
-bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplayId) {
-    const auto it = mHwcDisplaySlots.find(hwcDisplayId);
-    if (it == mHwcDisplaySlots.end()) {
-        LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid display");
+bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp) {
+    const auto displayId = toPhysicalDisplayId(hwcDisplayId);
+    if (!displayId) {
+        LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display");
         return false;
     }
 
-    const int32_t displayId = it->second;
-    RETURN_IF_INVALID_DISPLAY(displayId, false);
+    RETURN_IF_INVALID_DISPLAY(*displayId, false);
 
-    const auto& displayData = mDisplayData[displayId];
+    const auto& displayData = mDisplayData[*displayId];
     if (displayData.isVirtual) {
-        LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
+        LOG_DISPLAY_ERROR(*displayId, "Invalid operation on virtual display");
         return false;
     }
 
@@ -202,31 +197,26 @@
         // with the same timestamp when turning the display off and on. This
         // is a bug in the HWC implementation, but filter the extra events
         // out here so they don't cause havoc downstream.
-        if (timestamp == mLastHwVSync[displayId]) {
-            ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
-                    timestamp);
+        if (timestamp == mLastHwVSync[*displayId]) {
+            ALOGW("Ignoring duplicate VSYNC event from HWC for display %" PRIu64 " (t=%" PRId64 ")",
+                  *displayId, timestamp);
             return false;
         }
 
-        mLastHwVSync[displayId] = timestamp;
+        mLastHwVSync[*displayId] = timestamp;
     }
 
-    if (outDisplayId) {
-        *outDisplayId = displayId;
-    }
-
-    char tag[16];
-    snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", displayId);
-    ATRACE_INT(tag, ++mVSyncCounts[displayId] & 1);
+    const auto tag = "HW_VSYNC_" + std::to_string(*displayId);
+    ATRACE_INT(tag.c_str(), ++mVSyncCounts[*displayId] & 1);
 
     return true;
 }
 
-status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
-        ui::PixelFormat* format, int32_t *outId) {
+std::optional<DisplayId> HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
+                                                            ui::PixelFormat* format) {
     if (mRemainingHwcVirtualDisplays == 0) {
         ALOGE("%s: No remaining virtual displays", __FUNCTION__);
-        return NO_MEMORY;
+        return {};
     }
 
     if (SurfaceFlinger::maxVirtualDisplaySize != 0 &&
@@ -234,41 +224,33 @@
          height > SurfaceFlinger::maxVirtualDisplaySize)) {
         ALOGE("%s: Display size %ux%u exceeds maximum dimension of %" PRIu64, __FUNCTION__, width,
               height, SurfaceFlinger::maxVirtualDisplaySize);
-        return INVALID_OPERATION;
+        return {};
     }
-
     HWC2::Display* display;
     auto error = mHwcDevice->createVirtualDisplay(width, height, format,
             &display);
     if (error != HWC2::Error::None) {
         ALOGE("%s: Failed to create HWC virtual display", __FUNCTION__);
-        return NO_MEMORY;
+        return {};
     }
 
-    size_t displaySlot = 0;
-    if (!mFreeDisplaySlots.empty()) {
-        displaySlot = *mFreeDisplaySlots.begin();
-        mFreeDisplaySlots.erase(displaySlot);
-    } else if (mDisplayData.size() < INT32_MAX) {
-        // Don't bother allocating a slot larger than we can return
-        displaySlot = mDisplayData.size();
-        mDisplayData.resize(displaySlot + 1);
+    DisplayId displayId;
+    if (mFreeVirtualDisplayIds.empty()) {
+        displayId = getVirtualDisplayId(mNextVirtualDisplayId++);
     } else {
-        ALOGE("%s: Unable to allocate a display slot", __FUNCTION__);
-        return NO_MEMORY;
+        displayId = *mFreeVirtualDisplayIds.begin();
+        mFreeVirtualDisplayIds.erase(displayId);
     }
 
-    auto& displayData = mDisplayData[displaySlot];
+    auto& displayData = mDisplayData[displayId];
     displayData.hwcDisplay = display;
     displayData.isVirtual = true;
 
     --mRemainingHwcVirtualDisplays;
-    *outId = static_cast<int32_t>(displaySlot);
-
-    return NO_ERROR;
+    return displayId;
 }
 
-HWC2::Layer* HWComposer::createLayer(int32_t displayId) {
+HWC2::Layer* HWComposer::createLayer(DisplayId displayId) {
     RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
 
     auto display = mDisplayData[displayId].hwcDisplay;
@@ -278,7 +260,7 @@
     return layer;
 }
 
-void HWComposer::destroyLayer(int32_t displayId, HWC2::Layer* layer) {
+void HWComposer::destroyLayer(DisplayId displayId, HWC2::Layer* layer) {
     RETURN_IF_INVALID_DISPLAY(displayId);
 
     auto display = mDisplayData[displayId].hwcDisplay;
@@ -286,7 +268,8 @@
     RETURN_IF_HWC_ERROR(error, displayId);
 }
 
-nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const {
+nsecs_t HWComposer::getRefreshTimestamp(DisplayId displayId) const {
+    RETURN_IF_INVALID_DISPLAY(displayId, 0);
     // this returns the last refresh timestamp.
     // if the last one is not available, we estimate it based on
     // the refresh period and whatever closest timestamp we have.
@@ -296,17 +279,17 @@
     return now - ((now - mLastHwVSync[displayId]) % vsyncPeriod);
 }
 
-bool HWComposer::isConnected(int32_t displayId) const {
+bool HWComposer::isConnected(DisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, false);
-    return mDisplayData[displayId].hwcDisplay->isConnected();
+    return mDisplayData.at(displayId).hwcDisplay->isConnected();
 }
 
-std::vector<std::shared_ptr<const HWC2::Display::Config>>
-        HWComposer::getConfigs(int32_t displayId) const {
+std::vector<std::shared_ptr<const HWC2::Display::Config>> HWComposer::getConfigs(
+        DisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, {});
 
-    auto& displayData = mDisplayData[displayId];
-    auto configs = mDisplayData[displayId].hwcDisplay->getConfigs();
+    const auto& displayData = mDisplayData.at(displayId);
+    auto configs = displayData.hwcDisplay->getConfigs();
     if (displayData.configMap.empty()) {
         for (size_t i = 0; i < configs.size(); ++i) {
             displayData.configMap[i] = configs[i];
@@ -315,12 +298,12 @@
     return configs;
 }
 
-std::shared_ptr<const HWC2::Display::Config>
-        HWComposer::getActiveConfig(int32_t displayId) const {
+std::shared_ptr<const HWC2::Display::Config> HWComposer::getActiveConfig(
+        DisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
 
     std::shared_ptr<const HWC2::Display::Config> config;
-    auto error = mDisplayData[displayId].hwcDisplay->getActiveConfig(&config);
+    auto error = mDisplayData.at(displayId).hwcDisplay->getActiveConfig(&config);
     if (error == HWC2::Error::BadConfig) {
         LOG_DISPLAY_ERROR(displayId, "No active config");
         return nullptr;
@@ -336,11 +319,11 @@
     return config;
 }
 
-int HWComposer::getActiveConfigIndex(int32_t displayId) const {
+int HWComposer::getActiveConfigIndex(DisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, -1);
 
     int index;
-    auto error = mDisplayData[displayId].hwcDisplay->getActiveConfigIndex(&index);
+    auto error = mDisplayData.at(displayId).hwcDisplay->getActiveConfigIndex(&index);
     if (error == HWC2::Error::BadConfig) {
         LOG_DISPLAY_ERROR(displayId, "No active config");
         return -1;
@@ -356,17 +339,17 @@
     return index;
 }
 
-std::vector<ui::ColorMode> HWComposer::getColorModes(int32_t displayId) const {
+std::vector<ui::ColorMode> HWComposer::getColorModes(DisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, {});
 
     std::vector<ui::ColorMode> modes;
-    auto error = mDisplayData[displayId].hwcDisplay->getColorModes(&modes);
+    auto error = mDisplayData.at(displayId).hwcDisplay->getColorModes(&modes);
     RETURN_IF_HWC_ERROR(error, displayId, {});
     return modes;
 }
 
-status_t HWComposer::setActiveColorMode(int32_t displayId, ui::ColorMode mode,
-        ui::RenderIntent renderIntent) {
+status_t HWComposer::setActiveColorMode(DisplayId displayId, ui::ColorMode mode,
+                                        ui::RenderIntent renderIntent) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& displayData = mDisplayData[displayId];
@@ -379,8 +362,7 @@
     return NO_ERROR;
 }
 
-
-void HWComposer::setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled) {
+void HWComposer::setVsyncEnabled(DisplayId displayId, HWC2::Vsync enabled) {
     RETURN_IF_INVALID_DISPLAY(displayId);
     auto& displayData = mDisplayData[displayId];
 
@@ -401,37 +383,30 @@
 
         displayData.vsyncEnabled = enabled;
 
-        char tag[16];
-        snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", displayId);
-        ATRACE_INT(tag, enabled == HWC2::Vsync::Enable ? 1 : 0);
+        const auto tag = "HW_VSYNC_ON_" + std::to_string(displayId);
+        ATRACE_INT(tag.c_str(), enabled == HWC2::Vsync::Enable ? 1 : 0);
     }
 }
 
-status_t HWComposer::setClientTarget(int32_t displayId, uint32_t slot,
-        const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
-        ui::Dataspace dataspace) {
+status_t HWComposer::setClientTarget(DisplayId displayId, uint32_t slot,
+                                     const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
+                                     ui::Dataspace dataspace) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
-    ALOGV("setClientTarget for display %d", displayId);
+    ALOGV("setClientTarget for display %" PRIu64, displayId);
     auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
     auto error = hwcDisplay->setClientTarget(slot, target, acquireFence, dataspace);
     RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
     return NO_ERROR;
 }
 
-status_t HWComposer::prepare(DisplayDevice& display,
-        std::vector<CompositionInfo>& compositionData) {
+status_t HWComposer::prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData) {
     ATRACE_CALL();
 
-    Mutex::Autolock _l(mDisplayLock);
-    const auto displayId = display.getId();
-    if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
-        ALOGV("Skipping HWComposer prepare for non-HWC display");
-        return NO_ERROR;
-    }
-
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
+    Mutex::Autolock _l(mDisplayLock);
+
     auto& displayData = mDisplayData[displayId];
     auto& hwcDisplay = displayData.hwcDisplay;
     if (!hwcDisplay->isConnected()) {
@@ -501,7 +476,8 @@
                     changedTypes[&*hwcLayer]);
             compositionInfo.compositionType = changedTypes[&*hwcLayer];
             compositionInfo.layer->mLayer->setCompositionType(displayId,
-                    compositionInfo.compositionType, false);
+                                                              compositionInfo.compositionType,
+                                                              false);
         }
 
         switch (compositionInfo.compositionType) {
@@ -540,49 +516,48 @@
     return NO_ERROR;
 }
 
-bool HWComposer::hasDeviceComposition(int32_t displayId) const {
-    if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+bool HWComposer::hasDeviceComposition(const std::optional<DisplayId>& displayId) const {
+    if (!displayId) {
         // Displays without a corresponding HWC display are never composed by
         // the device
         return false;
     }
 
-    RETURN_IF_INVALID_DISPLAY(displayId, false);
-    return mDisplayData[displayId].hasDeviceComposition;
+    RETURN_IF_INVALID_DISPLAY(*displayId, false);
+    return mDisplayData.at(*displayId).hasDeviceComposition;
 }
 
-bool HWComposer::hasFlipClientTargetRequest(int32_t displayId) const {
-    if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+bool HWComposer::hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const {
+    if (!displayId) {
         // Displays without a corresponding HWC display are never composed by
         // the device
         return false;
     }
 
-    RETURN_IF_INVALID_DISPLAY(displayId, false);
-    return ((static_cast<uint32_t>(mDisplayData[displayId].displayRequests) &
+    RETURN_IF_INVALID_DISPLAY(*displayId, false);
+    return ((static_cast<uint32_t>(mDisplayData.at(*displayId).displayRequests) &
              static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0);
 }
 
-bool HWComposer::hasClientComposition(int32_t displayId) const {
-    if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+bool HWComposer::hasClientComposition(const std::optional<DisplayId>& displayId) const {
+    if (!displayId) {
         // Displays without a corresponding HWC display are always composed by
         // the client
         return true;
     }
 
-    RETURN_IF_INVALID_DISPLAY(displayId, true);
-    return mDisplayData[displayId].hasClientComposition;
+    RETURN_IF_INVALID_DISPLAY(*displayId, true);
+    return mDisplayData.at(*displayId).hasClientComposition;
 }
 
-sp<Fence> HWComposer::getPresentFence(int32_t displayId) const {
+sp<Fence> HWComposer::getPresentFence(DisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
-    return mDisplayData[displayId].lastPresentFence;
+    return mDisplayData.at(displayId).lastPresentFence;
 }
 
-sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId,
-        HWC2::Layer* layer) const {
+sp<Fence> HWComposer::getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const {
     RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
-    auto displayFences = mDisplayData[displayId].releaseFences;
+    auto displayFences = mDisplayData.at(displayId).releaseFences;
     if (displayFences.count(layer) == 0) {
         ALOGV("getLayerReleaseFence: Release fence not found");
         return Fence::NO_FENCE;
@@ -590,7 +565,7 @@
     return displayFences[layer];
 }
 
-status_t HWComposer::presentAndGetReleaseFences(int32_t displayId) {
+status_t HWComposer::presentAndGetReleaseFences(DisplayId displayId) {
     ATRACE_CALL();
 
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
@@ -618,8 +593,7 @@
     return NO_ERROR;
 }
 
-status_t HWComposer::setPowerMode(int32_t displayId, int32_t intMode) {
-    ALOGV("setPowerMode(%d, %d)", displayId, intMode);
+status_t HWComposer::setPowerMode(DisplayId displayId, int32_t intMode) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     const auto& displayData = mDisplayData[displayId];
@@ -675,7 +649,7 @@
     return NO_ERROR;
 }
 
-status_t HWComposer::setActiveConfig(int32_t displayId, size_t configId) {
+status_t HWComposer::setActiveConfig(DisplayId displayId, size_t configId) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& displayData = mDisplayData[displayId];
@@ -689,8 +663,7 @@
     return NO_ERROR;
 }
 
-status_t HWComposer::setColorTransform(int32_t displayId,
-        const mat4& transform) {
+status_t HWComposer::setColorTransform(DisplayId displayId, const mat4& transform) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& displayData = mDisplayData[displayId];
@@ -702,26 +675,34 @@
     return NO_ERROR;
 }
 
-void HWComposer::disconnectDisplay(int32_t displayId) {
+void HWComposer::disconnectDisplay(DisplayId displayId) {
     RETURN_IF_INVALID_DISPLAY(displayId);
     auto& displayData = mDisplayData[displayId];
 
     // If this was a virtual display, add its slot back for reuse by future
     // virtual displays
     if (displayData.isVirtual) {
-        mFreeDisplaySlots.insert(displayId);
+        mFreeVirtualDisplayIds.insert(displayId);
         ++mRemainingHwcVirtualDisplays;
     }
 
     const auto hwcDisplayId = displayData.hwcDisplay->getId();
-    mHwcDisplaySlots.erase(hwcDisplayId);
-    displayData = DisplayData();
+    mPhysicalDisplayIdMap.erase(hwcDisplayId);
+    mDisplayData.erase(displayId);
+    mVSyncCounts.erase(displayId);
+
+    // TODO(b/74619554): Select internal/external display from remaining displays.
+    if (hwcDisplayId == mInternalHwcDisplayId) {
+        mInternalHwcDisplayId.reset();
+    } else if (hwcDisplayId == mExternalHwcDisplayId) {
+        mExternalHwcDisplayId.reset();
+    }
 
     mHwcDevice->destroyDisplay(hwcDisplayId);
 }
 
-status_t HWComposer::setOutputBuffer(int32_t displayId,
-        const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
+status_t HWComposer::setOutputBuffer(DisplayId displayId, const sp<Fence>& acquireFence,
+                                     const sp<GraphicBuffer>& buffer) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
     const auto& displayData = mDisplayData[displayId];
 
@@ -735,13 +716,12 @@
     return NO_ERROR;
 }
 
-void HWComposer::clearReleaseFences(int32_t displayId) {
+void HWComposer::clearReleaseFences(DisplayId displayId) {
     RETURN_IF_INVALID_DISPLAY(displayId);
     mDisplayData[displayId].releaseFences.clear();
 }
 
-status_t HWComposer::getHdrCapabilities(
-        int32_t displayId, HdrCapabilities* outCapabilities) {
+status_t HWComposer::getHdrCapabilities(DisplayId displayId, HdrCapabilities* outCapabilities) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
@@ -750,22 +730,22 @@
     return NO_ERROR;
 }
 
-int32_t HWComposer::getSupportedPerFrameMetadata(int32_t displayId) const {
+int32_t HWComposer::getSupportedPerFrameMetadata(DisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, 0);
-    return mDisplayData[displayId].hwcDisplay->getSupportedPerFrameMetadata();
+    return mDisplayData.at(displayId).hwcDisplay->getSupportedPerFrameMetadata();
 }
 
-std::vector<ui::RenderIntent> HWComposer::getRenderIntents(int32_t displayId,
-        ui::ColorMode colorMode) const {
+std::vector<ui::RenderIntent> HWComposer::getRenderIntents(DisplayId displayId,
+                                                           ui::ColorMode colorMode) const {
     RETURN_IF_INVALID_DISPLAY(displayId, {});
 
     std::vector<ui::RenderIntent> renderIntents;
-    auto error = mDisplayData[displayId].hwcDisplay->getRenderIntents(colorMode, &renderIntents);
+    auto error = mDisplayData.at(displayId).hwcDisplay->getRenderIntents(colorMode, &renderIntents);
     RETURN_IF_HWC_ERROR(error, displayId, {});
     return renderIntents;
 }
 
-mat4 HWComposer::getDataspaceSaturationMatrix(int32_t displayId, ui::Dataspace dataspace) {
+mat4 HWComposer::getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace) {
     RETURN_IF_INVALID_DISPLAY(displayId, {});
 
     mat4 matrix;
@@ -806,23 +786,67 @@
     result.append(mHwcDevice->dump().c_str());
 }
 
-std::optional<hwc2_display_t>
-HWComposer::getHwcDisplayId(int32_t displayId) const {
-    if (!isValidDisplay(displayId)) {
+std::optional<DisplayId> HWComposer::toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const {
+    if (const auto it = mPhysicalDisplayIdMap.find(hwcDisplayId);
+        it != mPhysicalDisplayIdMap.end()) {
+        return it->second;
+    }
+    return {};
+}
+
+std::optional<hwc2_display_t> HWComposer::fromPhysicalDisplayId(DisplayId displayId) const {
+    if (const auto it = mDisplayData.find(displayId);
+        it != mDisplayData.end() && !it->second.isVirtual) {
+        return it->second.hwcDisplay->getId();
+    }
+    return {};
+}
+
+std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect(hwc2_display_t hwcDisplayId) {
+    if (isUsingVrComposer() && mInternalHwcDisplayId) {
+        ALOGE("Ignoring connection of external display %" PRIu64 " in VR mode", hwcDisplayId);
         return {};
     }
-    return mDisplayData[displayId].hwcDisplay->getId();
-}
 
-void HWComposer::setDisplayFrequencyScaleParameters(
-        HWC2::Device::FrequencyScaler frequencyScaler)
-{
-    mHwcDevice->setDisplayFrequencyScaleParameters(frequencyScaler);
-}
+    uint8_t port;
+    DisplayIdentificationData data;
+    const bool hasMultiDisplaySupport = getDisplayIdentificationData(hwcDisplayId, &port, &data);
 
-HWC2::Device::FrequencyScaler HWComposer::getDisplayFrequencyScaleParameters()
-{
-    return mHwcDevice->getDisplayFrequencyScaleParameters();
+    if (mPhysicalDisplayIdMap.empty()) {
+        mHasMultiDisplaySupport = hasMultiDisplaySupport;
+        ALOGI("Switching to %s multi-display mode",
+              hasMultiDisplaySupport ? "generalized" : "legacy");
+    } else if (mHasMultiDisplaySupport && !hasMultiDisplaySupport) {
+        ALOGE("Ignoring connection of display %" PRIu64 " without identification data",
+              hwcDisplayId);
+        return {};
+    }
+
+    std::optional<DisplayIdentificationInfo> info;
+
+    if (mHasMultiDisplaySupport) {
+        info = parseDisplayIdentificationData(port, data);
+        ALOGE_IF(!info, "Failed to parse identification data for display %" PRIu64, hwcDisplayId);
+    } else if (mInternalHwcDisplayId && mExternalHwcDisplayId) {
+        ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId);
+        return {};
+    } else {
+        ALOGW_IF(hasMultiDisplaySupport, "Ignoring identification data for display %" PRIu64,
+                 hwcDisplayId);
+        port = mInternalHwcDisplayId ? HWC_DISPLAY_EXTERNAL : HWC_DISPLAY_PRIMARY;
+    }
+
+    if (!mInternalHwcDisplayId) {
+        mInternalHwcDisplayId = hwcDisplayId;
+    } else if (!mExternalHwcDisplayId) {
+        mExternalHwcDisplayId = hwcDisplayId;
+    }
+
+    if (info) return info;
+
+    return DisplayIdentificationInfo{getFallbackDisplayId(port),
+                                     hwcDisplayId == mInternalHwcDisplayId ? "Internal display"
+                                                                           : "External display"};
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index cca1f3b..5074c2c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -34,7 +34,8 @@
 
 #include <memory>
 #include <optional>
-#include <set>
+#include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
 #include "DisplayIdentification.h"
@@ -82,101 +83,94 @@
 
     bool hasCapability(HWC2::Capability capability) const;
 
-    // Attempts to allocate a virtual display. If the virtual display is created
-    // on the HWC device, outId will contain its HWC ID.
-    status_t allocateVirtualDisplay(uint32_t width, uint32_t height,
-            ui::PixelFormat* format, int32_t* outId);
+    // Attempts to allocate a virtual display and returns its ID if created on the HWC device.
+    std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
+                                                    ui::PixelFormat* format);
 
     // Attempts to create a new layer on this display
-    HWC2::Layer* createLayer(int32_t displayId);
+    HWC2::Layer* createLayer(DisplayId displayId);
     // Destroy a previously created layer
-    void destroyLayer(int32_t displayId, HWC2::Layer* layer);
+    void destroyLayer(DisplayId displayId, HWC2::Layer* layer);
 
     // Asks the HAL what it can do
-    status_t prepare(DisplayDevice& display,
-            std::vector<CompositionInfo>& compositionData);
+    status_t prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData);
 
-    status_t setClientTarget(int32_t displayId, uint32_t slot,
-            const sp<Fence>& acquireFence,
-            const sp<GraphicBuffer>& target, ui::Dataspace dataspace);
+    status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp<Fence>& acquireFence,
+                             const sp<GraphicBuffer>& target, ui::Dataspace dataspace);
 
     // Present layers to the display and read releaseFences.
-    status_t presentAndGetReleaseFences(int32_t displayId);
+    status_t presentAndGetReleaseFences(DisplayId displayId);
 
     // set power mode
-    status_t setPowerMode(int32_t displayId, int mode);
+    status_t setPowerMode(DisplayId displayId, int mode);
 
     // set active config
-    status_t setActiveConfig(int32_t displayId, size_t configId);
+    status_t setActiveConfig(DisplayId displayId, size_t configId);
 
     // Sets a color transform to be applied to the result of composition
-    status_t setColorTransform(int32_t displayId, const mat4& transform);
+    status_t setColorTransform(DisplayId displayId, const mat4& transform);
 
     // reset state when an external, non-virtual display is disconnected
-    void disconnectDisplay(int32_t displayId);
+    void disconnectDisplay(DisplayId displayId);
 
     // does this display have layers handled by HWC
-    bool hasDeviceComposition(int32_t displayId) const;
+    bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const;
 
     // does this display have pending request to flip client target
-    bool hasFlipClientTargetRequest(int32_t displayId) const;
+    bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const;
 
     // does this display have layers handled by GLES
-    bool hasClientComposition(int32_t displayId) const;
+    bool hasClientComposition(const std::optional<DisplayId>& displayId) const;
 
     // get the present fence received from the last call to present.
-    sp<Fence> getPresentFence(int32_t displayId) const;
+    sp<Fence> getPresentFence(DisplayId displayId) const;
 
     // Get last release fence for the given layer
-    sp<Fence> getLayerReleaseFence(int32_t displayId,
-            HWC2::Layer* layer) const;
+    sp<Fence> getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const;
 
     // Set the output buffer and acquire fence for a virtual display.
     // Returns INVALID_OPERATION if displayId is not a virtual display.
-    status_t setOutputBuffer(int32_t displayId, const sp<Fence>& acquireFence,
-            const sp<GraphicBuffer>& buf);
+    status_t setOutputBuffer(DisplayId displayId, const sp<Fence>& acquireFence,
+                             const sp<GraphicBuffer>& buffer);
 
     // After SurfaceFlinger has retrieved the release fences for all the frames,
     // it can call this to clear the shared pointers in the release fence map
-    void clearReleaseFences(int32_t displayId);
+    void clearReleaseFences(DisplayId displayId);
 
     // Fetches the HDR capabilities of the given display
-    status_t getHdrCapabilities(int32_t displayId, HdrCapabilities* outCapabilities);
+    status_t getHdrCapabilities(DisplayId displayId, HdrCapabilities* outCapabilities);
 
-    int32_t getSupportedPerFrameMetadata(int32_t displayId) const;
+    int32_t getSupportedPerFrameMetadata(DisplayId displayId) const;
 
     // Returns the available RenderIntent of the given display.
-    std::vector<ui::RenderIntent> getRenderIntents(int32_t displayId, ui::ColorMode colorMode) const;
+    std::vector<ui::RenderIntent> getRenderIntents(DisplayId displayId,
+                                                   ui::ColorMode colorMode) const;
 
-    mat4 getDataspaceSaturationMatrix(int32_t displayId, ui::Dataspace dataspace);
+    mat4 getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace);
 
     // Events handling ---------------------------------------------------------
 
-    // Returns true if successful, false otherwise. The
-    // DisplayDevice::DisplayType of the display is returned as an output param.
-    bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplay);
-    std::optional<DisplayId> onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
-                                       HWC2::Connection connection);
+    // Returns stable display ID (and display name on connection of new or previously disconnected
+    // display), or std::nullopt if hotplug event was ignored.
+    std::optional<DisplayIdentificationInfo> onHotplug(hwc2_display_t hwcDisplayId,
+                                                       HWC2::Connection connection);
 
-    void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
+    bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp);
+    void setVsyncEnabled(DisplayId displayId, HWC2::Vsync enabled);
 
-    // Query display parameters.  Pass in a display index (e.g.
-    // HWC_DISPLAY_PRIMARY).
-    nsecs_t getRefreshTimestamp(int32_t displayId) const;
-    bool isConnected(int32_t displayId) const;
+    nsecs_t getRefreshTimestamp(DisplayId displayId) const;
+    bool isConnected(DisplayId displayId) const;
 
     // Non-const because it can update configMap inside of mDisplayData
-    std::vector<std::shared_ptr<const HWC2::Display::Config>>
-            getConfigs(int32_t displayId) const;
+    std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(DisplayId displayId) const;
 
-    std::shared_ptr<const HWC2::Display::Config>
-            getActiveConfig(int32_t displayId) const;
-    int getActiveConfigIndex(int32_t displayId) const;
+    std::shared_ptr<const HWC2::Display::Config> getActiveConfig(DisplayId displayId) const;
+    int getActiveConfigIndex(DisplayId displayId) const;
 
-    std::vector<ui::ColorMode> getColorModes(int32_t displayId) const;
+    std::vector<ui::ColorMode> getColorModes(DisplayId displayId) const;
 
-    status_t setActiveColorMode(int32_t displayId, ui::ColorMode mode,
-            ui::RenderIntent renderIntent);
+    status_t setActiveColorMode(DisplayId displayId, ui::ColorMode mode,
+                                ui::RenderIntent renderIntent);
 
     bool isUsingVrComposer() const;
 
@@ -185,20 +179,19 @@
 
     android::Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); }
 
-    std::optional<hwc2_display_t> getHwcDisplayId(int32_t displayId) const;
+    // TODO(b/74619554): Remove special cases for internal/external display.
+    std::optional<hwc2_display_t> getInternalHwcDisplayId() const { return mInternalHwcDisplayId; }
+    std::optional<hwc2_display_t> getExternalHwcDisplayId() const { return mExternalHwcDisplayId; }
 
-    // ------------------------------------------------------------------------
-    // These functions set and get the frequencyScaler.  The frequencyScaler holds
-    // a multiplier and divisor for virtually scaling the panel frequency in
-    // software.  This is used to simulate different panel frequencies when
-    // panel hardware is not available.
-    void setDisplayFrequencyScaleParameters(HWC2::Device::FrequencyScaler frequencyScaler);
-    HWC2::Device::FrequencyScaler getDisplayFrequencyScaleParameters();
+    std::optional<DisplayId> toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const;
+    std::optional<hwc2_display_t> fromPhysicalDisplayId(DisplayId displayId) const;
+
 private:
     // For unit tests
     friend TestableSurfaceFlinger;
 
-    bool isValidDisplay(int32_t displayId) const;
+    std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
+
     static void validateChange(HWC2::Composition from, HWC2::Composition to);
 
     struct cb_context;
@@ -223,21 +216,30 @@
         HWC2::Error presentError;
     };
 
-    std::unique_ptr<HWC2::Device>   mHwcDevice;
-    std::vector<DisplayData> mDisplayData{HWC_NUM_PHYSICAL_DISPLAY_TYPES};
-    std::set<size_t>                mFreeDisplaySlots;
-    std::unordered_map<hwc2_display_t, int32_t> mHwcDisplaySlots;
+    std::unordered_map<DisplayId, DisplayData> mDisplayData;
+
+    // This must be destroyed before mDisplayData, because destructor may call back into HWComposer
+    // and look up DisplayData.
+    std::unique_ptr<HWC2::Device> mHwcDevice;
+
+    std::unordered_map<hwc2_display_t, DisplayId> mPhysicalDisplayIdMap;
+    std::optional<hwc2_display_t> mInternalHwcDisplayId;
+    std::optional<hwc2_display_t> mExternalHwcDisplayId;
+    bool mHasMultiDisplaySupport = false;
+
     // protect mDisplayData from races between prepare and dump
     mutable Mutex mDisplayLock;
 
     cb_context* mCBContext = nullptr;
-    size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES]{0, 0};
+    std::unordered_map<DisplayId, size_t> mVSyncCounts;
+
+    std::unordered_set<uint32_t> mFreeVirtualDisplayIds;
+    uint32_t mNextVirtualDisplayId = 0;
     uint32_t mRemainingHwcVirtualDisplays{mHwcDevice->getMaxVirtualDisplayCount()};
 
     // protected by mLock
     mutable Mutex mLock;
-    mutable std::unordered_map<int32_t, nsecs_t> mLastHwVSync{
-            {{HWC_DISPLAY_PRIMARY, 0}, {HWC_DISPLAY_EXTERNAL, 0}}};
+    mutable std::unordered_map<DisplayId, nsecs_t> mLastHwVSync;
 
     // thread-safe
     mutable Mutex mVsyncLock;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index c111a27..5f3fcd6 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -48,34 +48,34 @@
     }
 }
 
-VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
-        const sp<IGraphicBufferProducer>& sink,
-        const sp<IGraphicBufferProducer>& bqProducer,
-        const sp<IGraphicBufferConsumer>& bqConsumer,
-        const std::string& name)
-:   ConsumerBase(bqConsumer),
-    mHwc(hwc),
-    mDisplayId(dispId),
-    mDisplayName(name),
-    mSource{},
-    mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
-    mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
-    mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
-    mProducerSlotSource(0),
-    mProducerBuffers(),
-    mQueueBufferOutput(),
-    mSinkBufferWidth(0),
-    mSinkBufferHeight(0),
-    mCompositionType(COMPOSITION_UNKNOWN),
-    mFbFence(Fence::NO_FENCE),
-    mOutputFence(Fence::NO_FENCE),
-    mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
-    mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
-    mDbgState(DBG_STATE_IDLE),
-    mDbgLastCompositionType(COMPOSITION_UNKNOWN),
-    mMustRecompose(false),
-    mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv)
-{
+VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc,
+                                             const std::optional<DisplayId>& displayId,
+                                             const sp<IGraphicBufferProducer>& sink,
+                                             const sp<IGraphicBufferProducer>& bqProducer,
+                                             const sp<IGraphicBufferConsumer>& bqConsumer,
+                                             const std::string& name)
+      : ConsumerBase(bqConsumer),
+        mHwc(hwc),
+        mDisplayId(displayId),
+        mDisplayName(name),
+        mSource{},
+        mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+        mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+        mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
+        mProducerSlotSource(0),
+        mProducerBuffers(),
+        mQueueBufferOutput(),
+        mSinkBufferWidth(0),
+        mSinkBufferHeight(0),
+        mCompositionType(COMPOSITION_UNKNOWN),
+        mFbFence(Fence::NO_FENCE),
+        mOutputFence(Fence::NO_FENCE),
+        mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
+        mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
+        mDbgState(DBG_STATE_IDLE),
+        mDbgLastCompositionType(COMPOSITION_UNKNOWN),
+        mMustRecompose(false),
+        mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv) {
     mSource[SOURCE_SINK] = sink;
     mSource[SOURCE_SCRATCH] = bqProducer;
 
@@ -107,8 +107,6 @@
     mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
     mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
     sink->setAsyncMode(true);
-    IGraphicBufferProducer::QueueBufferOutput output;
-    mSource[SOURCE_SCRATCH]->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &output);
 }
 
 VirtualDisplaySurface::~VirtualDisplaySurface() {
@@ -116,8 +114,9 @@
 }
 
 status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) {
-    if (mDisplayId < 0)
+    if (!mDisplayId) {
         return NO_ERROR;
+    }
 
     mMustRecompose = mustRecompose;
 
@@ -129,8 +128,9 @@
 }
 
 status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
-    if (mDisplayId < 0)
+    if (!mDisplayId) {
         return NO_ERROR;
+    }
 
     VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN,
             "Unexpected prepareFrame() in %s state", dbgStateStr());
@@ -177,8 +177,9 @@
 }
 
 status_t VirtualDisplaySurface::advanceFrame() {
-    if (mDisplayId < 0)
+    if (!mDisplayId) {
         return NO_ERROR;
+    }
 
     if (mCompositionType == COMPOSITION_HWC) {
         VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
@@ -211,7 +212,7 @@
 
     // At this point we know the output buffer acquire fence,
     // so update HWC state with it.
-    mHwc.setOutputBuffer(mDisplayId, mOutputFence, outBuffer);
+    mHwc.setOutputBuffer(*mDisplayId, mOutputFence, outBuffer);
 
     status_t result = NO_ERROR;
     if (fbBuffer != nullptr) {
@@ -221,22 +222,23 @@
                 &hwcSlot, &hwcBuffer);
 
         // TODO: Correctly propagate the dataspace from GL composition
-        result = mHwc.setClientTarget(mDisplayId, hwcSlot, mFbFence,
-                hwcBuffer, ui::Dataspace::UNKNOWN);
+        result = mHwc.setClientTarget(*mDisplayId, hwcSlot, mFbFence, hwcBuffer,
+                                      ui::Dataspace::UNKNOWN);
     }
 
     return result;
 }
 
 void VirtualDisplaySurface::onFrameCommitted() {
-    if (mDisplayId < 0)
+    if (!mDisplayId) {
         return;
+    }
 
     VDS_LOGW_IF(mDbgState != DBG_STATE_HWC,
             "Unexpected onFrameCommitted() in %s state", dbgStateStr());
     mDbgState = DBG_STATE_IDLE;
 
-    sp<Fence> retireFence = mHwc.getPresentFence(mDisplayId);
+    sp<Fence> retireFence = mHwc.getPresentFence(*mDisplayId);
     if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) {
         // release the scratch buffer back to the pool
         Mutex::Autolock lock(mMutex);
@@ -291,8 +293,9 @@
 
 status_t VirtualDisplaySurface::requestBuffer(int pslot,
         sp<GraphicBuffer>* outBuf) {
-    if (mDisplayId < 0)
+    if (!mDisplayId) {
         return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf);
+    }
 
     VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
             "Unexpected requestBuffer pslot=%d in %s state",
@@ -313,7 +316,7 @@
 
 status_t VirtualDisplaySurface::dequeueBuffer(Source source,
         PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
-    LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
+    LOG_FATAL_IF(!mDisplayId);
 
     status_t result =
             mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight,
@@ -359,7 +362,7 @@
                                               PixelFormat format, uint64_t usage,
                                               uint64_t* outBufferAge,
                                               FrameEventHistoryDelta* outTimestamps) {
-    if (mDisplayId < 0) {
+    if (!mDisplayId) {
         return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage, outBufferAge,
                                                    outTimestamps);
     }
@@ -446,8 +449,9 @@
 
 status_t VirtualDisplaySurface::queueBuffer(int pslot,
         const QueueBufferInput& input, QueueBufferOutput* output) {
-    if (mDisplayId < 0)
+    if (!mDisplayId) {
         return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output);
+    }
 
     VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
             "Unexpected queueBuffer(pslot=%d) in %s state", pslot,
@@ -504,8 +508,9 @@
 
 status_t VirtualDisplaySurface::cancelBuffer(int pslot,
         const sp<Fence>& fence) {
-    if (mDisplayId < 0)
+    if (!mDisplayId) {
         return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence);
+    }
 
     VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
             "Unexpected cancelBuffer(pslot=%d) in %s state", pslot,
@@ -616,6 +621,8 @@
 }
 
 status_t VirtualDisplaySurface::refreshOutputBuffer() {
+    LOG_FATAL_IF(!mDisplayId);
+
     if (mOutputProducerSlot >= 0) {
         mSource[SOURCE_SINK]->cancelBuffer(
                 mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot),
@@ -633,8 +640,8 @@
     // until after GLES calls queueBuffer(). So here we just set the buffer
     // (for use in HWC prepare) but not the fence; we'll call this again with
     // the proper fence once we have it.
-    result = mHwc.setOutputBuffer(mDisplayId, Fence::NO_FENCE,
-            mProducerBuffers[mOutputProducerSlot]);
+    result = mHwc.setOutputBuffer(*mDisplayId, Fence::NO_FENCE,
+                                  mProducerBuffers[mOutputProducerSlot]);
 
     return result;
 }
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 4bd4d0f..33678df 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -17,8 +17,10 @@
 #ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
 #define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
 
+#include <optional>
 #include <string>
 
+#include "DisplayIdentification.h"
 #include "DisplaySurface.h"
 #include "HWComposerBufferCache.h"
 
@@ -75,11 +77,10 @@
                               public BnGraphicBufferProducer,
                               private ConsumerBase {
 public:
-    VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
-            const sp<IGraphicBufferProducer>& sink,
-            const sp<IGraphicBufferProducer>& bqProducer,
-            const sp<IGraphicBufferConsumer>& bqConsumer,
-            const std::string& name);
+    VirtualDisplaySurface(HWComposer& hwc, const std::optional<DisplayId>& displayId,
+                          const sp<IGraphicBufferProducer>& sink,
+                          const sp<IGraphicBufferProducer>& bqProducer,
+                          const sp<IGraphicBufferConsumer>& bqConsumer, const std::string& name);
 
     //
     // DisplaySurface interface
@@ -154,7 +155,7 @@
     // Immutable after construction
     //
     HWComposer& mHwc;
-    const int32_t mDisplayId;
+    const std::optional<DisplayId> mDisplayId;
     const std::string mDisplayName;
     sp<IGraphicBufferProducer> mSource[2]; // indexed by SOURCE_*
     uint32_t mDefaultOutputFormat;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index dba5f8f..8882667 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -111,6 +111,8 @@
     args.flinger->getCompositorTiming(&compositorTiming);
     mFrameEventHistory.initializeCompositorTiming(compositorTiming);
     mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
+
+    mFlinger->onLayerCreated();
 }
 
 Layer::~Layer() {
@@ -119,13 +121,11 @@
         c->detachLayer(this);
     }
 
-    for (auto& point : mRemoteSyncPoints) {
-        point->setTransactionApplied();
-    }
-    for (auto& point : mLocalSyncPoints) {
-        point->setFrameAvailable();
-    }
     mFrameTracker.logAndResetStats(mName);
+
+    destroyAllHwcLayers();
+
+    mFlinger->onLayerDestroyed();
 }
 
 // ---------------------------------------------------------------------------
@@ -140,10 +140,9 @@
 void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
 
 void Layer::onRemovedFromCurrentState() {
+    mRemovedFromCurrentState = true;
+
     // the layer is removed from SF mCurrentState to mLayersPendingRemoval
-
-    mPendingRemoval = true;
-
     if (mCurrentState.zOrderRelativeOf != nullptr) {
         sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
         if (strongRelative != nullptr) {
@@ -153,22 +152,29 @@
         mCurrentState.zOrderRelativeOf = nullptr;
     }
 
+    // Since we are no longer reachable from CurrentState SurfaceFlinger
+    // will no longer invoke doTransaction for us, and so we will
+    // never finish applying transactions. We signal the sync point
+    // now so that another layer will not become indefinitely
+    // blocked.
+    for (auto& point: mRemoteSyncPoints) {
+        point->setTransactionApplied();
+    }
+    mRemoteSyncPoints.clear();
+
+    {
+    Mutex::Autolock syncLock(mLocalSyncPointMutex);
+    for (auto& point : mLocalSyncPoints) {
+        point->setFrameAvailable();
+    }
+    mLocalSyncPoints.clear();
+    }
+
     for (const auto& child : mCurrentChildren) {
         child->onRemovedFromCurrentState();
     }
 }
 
-void Layer::onRemoved() {
-    // the layer is removed from SF mLayersPendingRemoval
-    abandon();
-
-    destroyAllHwcLayers();
-
-    for (const auto& child : mCurrentChildren) {
-        child->onRemoved();
-    }
-}
-
 // ---------------------------------------------------------------------------
 // set-up
 // ---------------------------------------------------------------------------
@@ -190,9 +196,9 @@
 // h/w composer set-up
 // ---------------------------------------------------------------------------
 
-bool Layer::createHwcLayer(HWComposer* hwc, int32_t displayId) {
+bool Layer::createHwcLayer(HWComposer* hwc, DisplayId displayId) {
     LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(displayId) != 0,
-                        "Already have a layer for display %d", displayId);
+                        "Already have a layer for display %" PRIu64, displayId);
     auto layer = std::shared_ptr<HWC2::Layer>(
             hwc->createLayer(displayId),
             [hwc, displayId](HWC2::Layer* layer) {
@@ -208,7 +214,7 @@
     return true;
 }
 
-bool Layer::destroyHwcLayer(int32_t displayId) {
+bool Layer::destroyHwcLayer(DisplayId displayId) {
     if (getBE().mHwcLayers.count(displayId) == 0) {
         return false;
     }
@@ -228,6 +234,10 @@
     }
     LOG_ALWAYS_FATAL_IF(!getBE().mHwcLayers.empty(),
                         "All hardware composer layers should have been destroyed");
+
+    for (const sp<Layer>& child : mDrawingChildren) {
+        child->destroyAllHwcLayers();
+    }
 }
 
 Rect Layer::getContentCrop() const {
@@ -464,12 +474,13 @@
 
 void Layer::setGeometry(const sp<const DisplayDevice>& display, uint32_t z) {
     const auto displayId = display->getId();
-    if (!hasHwcLayer(displayId)) {
-        ALOGE("[%s] failed to setGeometry: no HWC layer found (%d)",
-              mName.string(), displayId);
+    LOG_ALWAYS_FATAL_IF(!displayId);
+    if (!hasHwcLayer(*displayId)) {
+        ALOGE("[%s] failed to setGeometry: no HWC layer found for display %" PRIu64, mName.string(),
+              *displayId);
         return;
     }
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
+    auto& hwcInfo = getBE().mHwcLayers[*displayId];
 
     // enable this layer
     hwcInfo.forceClientComposition = false;
@@ -621,7 +632,7 @@
     if (orientation & ui::Transform::ROT_INVALID) {
         // we can only handle simple transformation
         hwcInfo.forceClientComposition = true;
-        getBE().mHwcLayers[displayId].compositionType = HWC2::Composition::Client;
+        getBE().mHwcLayers[*displayId].compositionType = HWC2::Composition::Client;
     } else {
         auto transform = static_cast<HWC2::Transform>(orientation);
         hwcInfo.transform = transform;
@@ -635,18 +646,18 @@
     }
 }
 
-void Layer::forceClientComposition(int32_t displayId) {
+void Layer::forceClientComposition(DisplayId displayId) {
     if (getBE().mHwcLayers.count(displayId) == 0) {
-        ALOGE("forceClientComposition: no HWC layer found (%d)", displayId);
+        ALOGE("forceClientComposition: no HWC layer found (display %" PRIu64 ")", displayId);
         return;
     }
 
     getBE().mHwcLayers[displayId].forceClientComposition = true;
 }
 
-bool Layer::getForceClientComposition(int32_t displayId) {
+bool Layer::getForceClientComposition(DisplayId displayId) {
     if (getBE().mHwcLayers.count(displayId) == 0) {
-        ALOGE("getForceClientComposition: no HWC layer found (%d)", displayId);
+        ALOGE("getForceClientComposition: no HWC layer found (display %" PRIu64 ")", displayId);
         return false;
     }
 
@@ -655,7 +666,7 @@
 
 void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
     const auto displayId = display->getId();
-    if (getBE().mHwcLayers.count(displayId) == 0 ||
+    if (getBE().mHwcLayers.count(*displayId) == 0 ||
         getCompositionType(displayId) != HWC2::Composition::Cursor) {
         return;
     }
@@ -678,8 +689,8 @@
     auto position = displayTransform.transform(frame);
 
     auto error =
-            (getBE().mHwcLayers[displayId].layer)->setCursorPosition(
-                    position.left, position.top);
+            getBE().mHwcLayers[*displayId].layer->setCursorPosition(position.left, position.top);
+
     ALOGE_IF(error != HWC2::Error::None,
              "[%s] Failed to set cursor position "
              "to (%d, %d): %s (%d)",
@@ -711,7 +722,7 @@
     clearWithOpenGL(renderArea, 0, 0, 0, 0);
 }
 
-void Layer::setCompositionType(int32_t displayId, HWC2::Composition type, bool callIntoHwc) {
+void Layer::setCompositionType(DisplayId displayId, HWC2::Composition type, bool callIntoHwc) {
     if (getBE().mHwcLayers.count(displayId) == 0) {
         ALOGE("setCompositionType called without a valid HWC layer");
         return;
@@ -734,16 +745,20 @@
     }
 }
 
-HWC2::Composition Layer::getCompositionType(int32_t displayId) const {
-    if (getBE().mHwcLayers.count(displayId) == 0) {
+HWC2::Composition Layer::getCompositionType(const std::optional<DisplayId>& displayId) const {
+    if (!displayId) {
         // If we're querying the composition type for a display that does not
         // have a HWC counterpart, then it will always be Client
         return HWC2::Composition::Client;
     }
-    return getBE().mHwcLayers[displayId].compositionType;
+    if (getBE().mHwcLayers.count(*displayId) == 0) {
+        ALOGE("getCompositionType called with an invalid HWC layer");
+        return HWC2::Composition::Invalid;
+    }
+    return getBE().mHwcLayers.at(*displayId).compositionType;
 }
 
-void Layer::setClearClientTarget(int32_t displayId, bool clear) {
+void Layer::setClearClientTarget(DisplayId displayId, bool clear) {
     if (getBE().mHwcLayers.count(displayId) == 0) {
         ALOGE("setClearClientTarget called without a valid HWC layer");
         return;
@@ -751,7 +766,7 @@
     getBE().mHwcLayers[displayId].clearClientTarget = clear;
 }
 
-bool Layer::getClearClientTarget(int32_t displayId) const {
+bool Layer::getClearClientTarget(DisplayId displayId) const {
     if (getBE().mHwcLayers.count(displayId) == 0) {
         ALOGE("getClearClientTarget called without a valid HWC layer");
         return false;
@@ -765,6 +780,9 @@
         // relevant frame
         return false;
     }
+    if (isRemovedFromCurrentState()) {
+        return false;
+    }
 
     Mutex::Autolock lock(mLocalSyncPointMutex);
     mLocalSyncPoints.push_back(point);
@@ -838,7 +856,9 @@
 
     // If this transaction is waiting on the receipt of a frame, generate a sync
     // point and send it to the remote layer.
-    if (mCurrentState.barrierLayer_legacy != nullptr) {
+    // We don't allow installing sync points after we are removed from the current state
+    // as we won't be able to signal our end.
+    if (mCurrentState.barrierLayer_legacy != nullptr && !isRemovedFromCurrentState()) {
         sp<Layer> barrierLayer = mCurrentState.barrierLayer_legacy.promote();
         if (barrierLayer == nullptr) {
             ALOGE("[%s] Unable to promote barrier Layer.", mName.string());
@@ -1047,6 +1067,7 @@
 
     // Commit the transaction
     commitTransaction(c);
+    mCurrentState.callbackHandles = {};
     return flags;
 }
 
@@ -1414,7 +1435,7 @@
     result.append("-----------------------------\n");
 }
 
-void Layer::miniDump(String8& result, int32_t displayId) const {
+void Layer::miniDump(String8& result, DisplayId displayId) const {
     if (getBE().mHwcLayers.count(displayId) == 0) {
         return;
     }
@@ -1489,9 +1510,8 @@
 void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
                                      FrameEventHistoryDelta* outDelta) {
     if (newTimestamps) {
-        const int32_t layerID = getSequence();
-        mTimeStats.setLayerName(layerID, getName().c_str());
-        mTimeStats.setPostTime(layerID, newTimestamps->frameNumber, newTimestamps->postedTime);
+        mTimeStats.setPostTime(getSequence(), newTimestamps->frameNumber, getName().c_str(),
+                               newTimestamps->postedTime);
     }
 
     Mutex::Autolock lock(mFrameEventHistoryMutex);
@@ -1979,7 +1999,7 @@
     }
 }
 
-void Layer::writeToProto(LayerProto* layerInfo, int32_t displayId) {
+void Layer::writeToProto(LayerProto* layerInfo, DisplayId displayId) {
     if (!hasHwcLayer(displayId)) {
         return;
     }
@@ -2008,6 +2028,10 @@
     }
 }
 
+bool Layer::isRemovedFromCurrentState() const  {
+    return mRemovedFromCurrentState;
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 21729ad..9b9b91b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -38,6 +38,7 @@
 
 #include <cstdint>
 #include <list>
+#include <optional>
 #include <vector>
 
 #include "Client.h"
@@ -47,6 +48,7 @@
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
 #include "TimeStats/TimeStats.h"
+#include "TransactionCompletedThread.h"
 
 #include "DisplayHardware/HWComposer.h"
 #include "DisplayHardware/HWComposerBufferCache.h"
@@ -183,6 +185,10 @@
         sp<NativeHandle> sidebandStream;
         mat4 colorTransform;
         bool hasColorTransform;
+
+        // The deque of callback handles for this frame. The back of the deque contains the most
+        // recent callback handle.
+        std::deque<sp<CallbackHandle>> callbackHandles;
     };
 
     explicit Layer(const LayerCreationArgs& args);
@@ -265,13 +271,17 @@
     virtual bool setTransform(uint32_t /*transform*/) { return false; };
     virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
     virtual bool setCrop(const Rect& /*crop*/) { return false; };
-    virtual bool setBuffer(sp<GraphicBuffer> /*buffer*/) { return false; };
+    virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/) { return false; };
     virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
     virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; };
     virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; };
     virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; };
     virtual bool setApi(int32_t /*api*/) { return false; };
     virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
+    virtual bool setTransactionCompletedListeners(
+            const std::vector<sp<CallbackHandle>>& /*handles*/) {
+        return false;
+    };
 
     ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
 
@@ -346,12 +356,12 @@
     virtual bool isCreatedFromMainThread() const { return false; }
 
 
-    bool isPendingRemoval() const { return mPendingRemoval; }
+    bool isRemovedFromCurrentState() const;
 
     void writeToProto(LayerProto* layerInfo,
                       LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
 
-    void writeToProto(LayerProto* layerInfo, int32_t displayId);
+    void writeToProto(LayerProto* layerInfo, DisplayId displayId);
 
     virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
     virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
@@ -377,16 +387,17 @@
     virtual bool isHdrY410() const { return false; }
 
     void setGeometry(const sp<const DisplayDevice>& display, uint32_t z);
-    void forceClientComposition(int32_t displayId);
-    bool getForceClientComposition(int32_t displayId);
-    virtual void setPerFrameData(const sp<const DisplayDevice>& display) = 0;
+    void forceClientComposition(DisplayId displayId);
+    bool getForceClientComposition(DisplayId displayId);
+    virtual void setPerFrameData(DisplayId displayId, const ui::Transform& transform,
+                                 const Rect& viewport, int32_t supportedPerFrameMetadata) = 0;
 
     // callIntoHwc exists so we can update our local state and call
     // acceptDisplayChanges without unnecessarily updating the device's state
-    void setCompositionType(int32_t displayId, HWC2::Composition type, bool callIntoHwc = true);
-    HWC2::Composition getCompositionType(int32_t displayId) const;
-    void setClearClientTarget(int32_t displayId, bool clear);
-    bool getClearClientTarget(int32_t displayId) const;
+    void setCompositionType(DisplayId displayId, HWC2::Composition type, bool callIntoHwc = true);
+    HWC2::Composition getCompositionType(const std::optional<DisplayId>& displayId) const;
+    void setClearClientTarget(DisplayId displayId, bool clear);
+    bool getClearClientTarget(DisplayId displayId) const;
     void updateCursorPosition(const sp<const DisplayDevice>& display);
 
     /*
@@ -394,8 +405,6 @@
      */
     virtual void onLayerDisplayed(const sp<Fence>& releaseFence);
 
-    virtual void abandon() {}
-
     virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
     virtual void setTransformHint(uint32_t /*orientation*/) const { }
 
@@ -403,13 +412,14 @@
      * called before composition.
      * returns true if the layer has pending updates.
      */
-    virtual bool onPreComposition(nsecs_t /*refreshStartTime*/) { return true; }
+    virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
 
     /*
      * called after composition.
      * returns true if the layer latched a new buffer this frame.
      */
-    virtual bool onPostComposition(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+    virtual bool onPostComposition(const std::optional<DisplayId>& /*displayId*/,
+                                   const std::shared_ptr<FenceTime>& /*glDoneFence*/,
                                    const std::shared_ptr<FenceTime>& /*presentFence*/,
                                    const CompositorTiming& /*compositorTiming*/) {
         return false;
@@ -475,12 +485,6 @@
      */
     void onRemovedFromCurrentState();
 
-    /*
-     * called with the state lock from the main thread when the layer is
-     * removed from the pending removal list
-     */
-    void onRemoved();
-
     // Updates the transform hint in our SurfaceFlingerConsumer to match
     // the current orientation of the display device.
     void updateTransformHint(const sp<const DisplayDevice>& display) const;
@@ -500,24 +504,24 @@
 
     // -----------------------------------------------------------------------
 
-    bool createHwcLayer(HWComposer* hwc, int32_t displayId);
-    bool destroyHwcLayer(int32_t displayId);
+    bool createHwcLayer(HWComposer* hwc, DisplayId displayId);
+    bool destroyHwcLayer(DisplayId displayId);
     void destroyAllHwcLayers();
 
-    bool hasHwcLayer(int32_t displayId) { return getBE().mHwcLayers.count(displayId) > 0; }
+    bool hasHwcLayer(DisplayId displayId) { return getBE().mHwcLayers.count(displayId) > 0; }
 
-    HWC2::Layer* getHwcLayer(int32_t displayId) {
-        if (getBE().mHwcLayers.count(displayId) == 0) {
+    HWC2::Layer* getHwcLayer(DisplayId displayId) {
+        if (!hasHwcLayer(displayId)) {
             return nullptr;
         }
         return getBE().mHwcLayers[displayId].layer.get();
     }
 
-    bool setHwcLayer(int32_t hwcId) {
-        if (getBE().mHwcLayers.count(hwcId) == 0) {
+    bool setHwcLayer(DisplayId displayId) {
+        if (!hasHwcLayer(displayId)) {
             return false;
         }
-        getBE().compositionInfo.hwc.hwcLayer = getBE().mHwcLayers[hwcId].layer;
+        getBE().compositionInfo.hwc.hwcLayer = getBE().mHwcLayers[displayId].layer;
         return true;
     }
 
@@ -532,7 +536,7 @@
 
     /* always call base class first */
     static void miniDumpHeader(String8& result);
-    void miniDump(String8& result, int32_t displayId) const;
+    void miniDump(String8& result, DisplayId displayId) const;
     void dumpFrameStats(String8& result) const;
     void dumpFrameEvents(String8& result);
     void clearFrameStats();
@@ -595,12 +599,12 @@
      */
     class LayerCleaner {
         sp<SurfaceFlinger> mFlinger;
-        wp<Layer> mLayer;
+        sp<Layer> mLayer;
 
     protected:
         ~LayerCleaner() {
             // destroy client resources
-            mFlinger->onLayerDestroyed(mLayer);
+            mFlinger->onHandleDestroyed(mLayer);
         }
 
     public:
@@ -702,6 +706,8 @@
     virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
     bool getPremultipledAlpha() const;
 
+    bool mPendingHWCDestroy{false};
+
 protected:
     // -----------------------------------------------------------------------
     bool usingRelativeZ(LayerVector::StateSet stateSet);
@@ -745,7 +751,7 @@
     // Whether filtering is needed b/c of the drawingstate
     bool mNeedsFiltering{false};
 
-    bool mPendingRemoval{false};
+    std::atomic<bool> mRemovedFromCurrentState{false};
 
     // page-flip thread (currently main thread)
     bool mProtectedByApp{false}; // application requires protected path to external sink
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index 463c46c..3f5134e 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -24,6 +24,7 @@
 #include <renderengine/Texture.h>
 #include <ui/Region.h>
 
+#include "DisplayHardware/DisplayIdentification.h"
 #include "DisplayHardware/HWComposer.h"
 #include "DisplayHardware/HWComposerBufferCache.h"
 #include "SurfaceFlinger.h"
@@ -41,7 +42,7 @@
     std::shared_ptr<LayerBE> layer;
     struct {
         std::shared_ptr<HWC2::Layer> hwcLayer;
-        int32_t displayId = -1;
+        DisplayId displayId;
         sp<Fence> fence;
         HWC2::BlendMode blendMode = HWC2::BlendMode::Invalid;
         Rect displayFrame;
@@ -123,12 +124,11 @@
         HWC2::Transform transform;
     };
 
-
     // A layer can be attached to multiple displays when operating in mirror mode
     // (a.k.a: when several displays are attached with equal layerStack). In this
     // case we need to keep track. In non-mirror mode, a layer will have only one
-    // HWCInfo. This map key is a display layerStack.
-    std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+    // HWCInfo.
+    std::unordered_map<DisplayId, HWCInfo> mHwcLayers;
 
     CompositionInfo compositionInfo;
 };
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 3c11e73..9bad6de 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -1,5 +1,6 @@
 #pragma once
 
+#include <ui/GraphicTypes.h>
 #include <ui/Transform.h>
 
 #include <functional>
@@ -19,9 +20,11 @@
     static float getCaptureFillValue(CaptureFill captureFill);
 
     RenderArea(uint32_t reqWidth, uint32_t reqHeight, CaptureFill captureFill,
+               ui::Dataspace reqDataSpace,
                ui::Transform::orientation_flags rotation = ui::Transform::ROT_0)
           : mReqWidth(reqWidth),
             mReqHeight(reqHeight),
+            mReqDataSpace(reqDataSpace),
             mCaptureFill(captureFill),
             mRotationFlags(rotation) {}
 
@@ -66,6 +69,9 @@
     int getReqWidth() const { return mReqWidth; };
     int getReqHeight() const { return mReqHeight; };
 
+    // Returns the composition data space of the render area.
+    ui::Dataspace getReqDataSpace() const { return mReqDataSpace; }
+
     // Returns the fill color of the physical render area.  Regions not
     // covered by any rendered layer should be filled with this color.
     CaptureFill getCaptureFill() const { return mCaptureFill; };
@@ -73,6 +79,7 @@
 private:
     const uint32_t mReqWidth;
     const uint32_t mReqHeight;
+    const ui::Dataspace mReqDataSpace;
     const CaptureFill mCaptureFill;
     const ui::Transform::orientation_flags mRotationFlags;
 };
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index cba9181..172c418 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -25,6 +25,7 @@
 #include <algorithm>
 
 #include <log/log.h>
+#include <cutils/properties.h>
 #include <utils/String8.h>
 #include <utils/Thread.h>
 #include <utils/Trace.h>
@@ -520,27 +521,12 @@
 
 void DispSync::setPeriod(nsecs_t period) {
     Mutex::Autolock lock(mMutex);
-    mPeriodBase = mPeriod = period;
+    mPeriod = period;
     mPhase = 0;
     mReferenceTime = 0;
     mThread->updateModel(mPeriod, mPhase, mReferenceTime);
 }
 
-void DispSync::scalePeriod(HWC2::Device::FrequencyScaler frequencyScaler) {
-    Mutex::Autolock lock(mMutex);
-
-    // if only 1 of the properties is updated, we will get to this
-    // point "attempting" to set the scale to 1 when it is already
-    // 1.  Check that special case so that we don't do a useless
-    // update of the model.
-    if ((frequencyScaler.multiplier == 1) &&
-            (frequencyScaler.divisor == 1) &&
-            (mPeriod == mPeriodBase)) return;
-
-    mPeriod = mPeriodBase * frequencyScaler.multiplier / frequencyScaler.divisor;
-    mThread->updateModel(mPeriod, mPhase, mReferenceTime);
-}
-
 nsecs_t DispSync::getPeriod() {
     // lock mutex as mPeriod changes multiple times in updateModelLocked
     Mutex::Autolock lock(mMutex);
@@ -565,7 +551,7 @@
 
         // Exclude the min and max from the average
         durationSum -= minDuration + maxDuration;
-        mPeriodBase = mPeriod = durationSum / (mNumResyncSamples - 3);
+        mPeriod = durationSum / (mNumResyncSamples - 3);
 
         ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));
 
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 5b511f4..5d19093 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -24,7 +24,6 @@
 #include <utils/Timers.h>
 
 #include <ui/FenceTime.h>
-#include <DisplayHardware/HWC2.h>
 
 #include <memory>
 
@@ -49,7 +48,6 @@
     virtual bool addResyncSample(nsecs_t timestamp) = 0;
     virtual void endResync() = 0;
     virtual void setPeriod(nsecs_t period) = 0;
-    virtual void scalePeriod(HWC2::Device::FrequencyScaler) = 0;
     virtual nsecs_t getPeriod() = 0;
     virtual void setRefreshSkipCount(int count) = 0;
     virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback) = 0;
@@ -120,12 +118,6 @@
     // turned on.  It should NOT be used after that.
     void setPeriod(nsecs_t period) override;
 
-    // The scalePeriod method applies the multiplier and divisor to
-    // scale the vsync event model's period.   The function is added
-    // for an experimental test mode and should not be used outside
-    // of that purpose.
-    void scalePeriod(HWC2::Device::FrequencyScaler frequencyScaler);
-
     // The getPeriod method returns the current vsync period.
     nsecs_t getPeriod() override;
 
@@ -188,7 +180,6 @@
     // mPeriod is the computed period of the modeled vsync events in
     // nanoseconds.
     nsecs_t mPeriod;
-    nsecs_t mPeriodBase;
 
     // mPhase is the phase offset of the modeled vsync events.  It is the
     // number of nanoseconds from time 0 to the first vsync event.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 18a8bb1..4286cc9 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include "Scheduler.h"
 
 #include <cinttypes>
 #include <cstdint>
 #include <memory>
+#include <numeric>
 
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
@@ -27,6 +30,7 @@
 
 #include <gui/ISurfaceComposer.h>
 #include <ui/DisplayStatInfo.h>
+#include <utils/Trace.h>
 
 #include "DispSync.h"
 #include "DispSyncSource.h"
@@ -196,4 +200,58 @@
     mPrimaryDispSync->setIgnorePresentFences(ignore);
 }
 
+void Scheduler::makeHWSyncAvailable(bool makeAvailable) {
+    std::lock_guard<std::mutex> lock(mHWVsyncLock);
+    mHWVsyncAvailable = makeAvailable;
+}
+
+void Scheduler::addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp) {
+    ATRACE_INT("AutoTimestamp", isAutoTimestamp);
+    // Video does not have timestamp automatically set, so we discard timestamps that are
+    // coming in from other sources for now.
+    if (isAutoTimestamp) {
+        return;
+    }
+    int64_t differenceMs = (newFrameTimestamp - mPreviousFrameTimestamp) / 1000000;
+    mPreviousFrameTimestamp = newFrameTimestamp;
+
+    if (differenceMs < 10 || differenceMs > 100) {
+        // Dismiss noise.
+        return;
+    }
+    ATRACE_INT("TimestampDiff", differenceMs);
+
+    mTimeDifferences[mCounter % ARRAY_SIZE] = differenceMs;
+    mCounter++;
+    nsecs_t average = calculateAverage();
+    ATRACE_INT("TimestampAverage", average);
+
+    // TODO(b/113612090): This are current numbers from trial and error while running videos
+    // from YouTube at 24, 30, and 60 fps.
+    if (average > 14 && average < 18) {
+        ATRACE_INT("FPS", 60);
+    } else if (average > 31 && average < 34) {
+        ATRACE_INT("FPS", 30);
+        updateFrameSkipping(1);
+        return;
+    } else if (average > 39 && average < 42) {
+        ATRACE_INT("FPS", 24);
+    }
+    updateFrameSkipping(0);
+}
+
+nsecs_t Scheduler::calculateAverage() const {
+    nsecs_t sum = std::accumulate(mTimeDifferences.begin(), mTimeDifferences.end(), 0);
+    return (sum / ARRAY_SIZE);
+}
+
+void Scheduler::updateFrameSkipping(const int64_t skipCount) {
+    ATRACE_INT("FrameSkipCount", skipCount);
+    if (mSkipCount != skipCount) {
+        // Only update DispSync if it hasn't been updated yet.
+        mPrimaryDispSync->setRefreshSkipCount(skipCount);
+        mSkipCount = skipCount;
+    }
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index fdafe58..dd1f24b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -102,6 +102,8 @@
     void addResyncSample(const nsecs_t timestamp);
     void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
     void setIgnorePresentFences(bool ignore);
+    void makeHWSyncAvailable(bool makeAvailable);
+    void addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp);
 
 protected:
     virtual std::unique_ptr<EventThread> makeEventThread(
@@ -110,6 +112,9 @@
             impl::EventThread::InterceptVSyncsCallback interceptCallback);
 
 private:
+    nsecs_t calculateAverage() const;
+    void updateFrameSkipping(const int64_t skipCount);
+
     // TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it
     // should make request to Scheduler to compute next refresh.
     friend class BufferQueueLayer;
@@ -133,6 +138,18 @@
 
     std::unique_ptr<DispSync> mPrimaryDispSync;
     std::unique_ptr<EventControlThread> mEventControlThread;
+
+    // TODO(b/113612090): The following set of variables needs to be revised. For now, this is
+    // a proof of concept. We turn on frame skipping if the difference between the timestamps
+    // is between 32 and 34ms. We expect this currently for 30fps videos, so we render them at 30Hz.
+    nsecs_t mPreviousFrameTimestamp = 0;
+    // Keeping track of whether we are skipping the refresh count. If we want to
+    // simulate 30Hz rendering, we skip every other frame, and this variable is set
+    // to 1.
+    int64_t mSkipCount = 0;
+    static constexpr size_t ARRAY_SIZE = 30;
+    std::array<int64_t, ARRAY_SIZE> mTimeDifferences;
+    size_t mCounter = 0;
 };
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4a96e89..ce3fb2d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -45,6 +45,7 @@
 #include <gui/BufferQueue.h>
 #include <gui/GuiConfig.h>
 #include <gui/IDisplayEventConnection.h>
+#include <gui/IProducerListener.h>
 #include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 #include <renderengine/RenderEngine.h>
@@ -75,7 +76,9 @@
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
 #include "NativeWindowSurface.h"
+#include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
+#include "SurfaceInterceptor.h"
 
 #include "DisplayHardware/ComposerHal.h"
 #include "DisplayHardware/DisplayIdentification.h"
@@ -88,6 +91,7 @@
 #include "Scheduler/EventControlThread.h"
 #include "Scheduler/EventThread.h"
 #include "Scheduler/InjectVSyncSource.h"
+#include "Scheduler/MessageQueue.h"
 #include "Scheduler/Scheduler.h"
 
 #include <cutils/compiler.h>
@@ -102,8 +106,6 @@
 
 #include <layerproto/LayerProtoParser.h>
 
-#define DISPLAY_COUNT       1
-
 namespace android {
 
 using namespace android::hardware::configstore;
@@ -170,6 +172,11 @@
     bool mLocked;
 };
 
+// Currently we only support V0_SRGB and DISPLAY_P3 as composition preference.
+bool validateCompositionDataspace(Dataspace dataspace) {
+    return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
+}
+
 }  // namespace anonymous
 
 // ---------------------------------------------------------------------------
@@ -188,13 +195,14 @@
 bool SurfaceFlinger::hasSyncFramework;
 bool SurfaceFlinger::useVrFlinger;
 int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
-// TODO(courtneygo): Rename hasWideColorDisplay to clarify its actual meaning.
 bool SurfaceFlinger::hasWideColorDisplay;
 int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
 bool SurfaceFlinger::useColorManagement;
 bool SurfaceFlinger::useContextPriority;
-Dataspace SurfaceFlinger::compositionDataSpace = Dataspace::V0_SRGB;
-ui::PixelFormat SurfaceFlinger::compositionPixelFormat = ui::PixelFormat::RGBA_8888;
+Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
+Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
 
 std::string getHwcServiceName() {
     char value[PROPERTY_VALUE_MAX] = {};
@@ -233,14 +241,15 @@
         mComposerSequenceId(0) {
 }
 
-SurfaceFlinger::SurfaceFlinger(SurfaceFlinger::SkipInitializationTag)
+SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory,
+                               SurfaceFlinger::SkipInitializationTag)
       : BnSurfaceComposer(),
+        mFactory(factory),
         mTransactionPending(false),
         mAnimTransactionPending(false),
         mLayersRemoved(false),
         mLayersAdded(false),
         mBootTime(systemTime()),
-        mDisplayTokens(),
         mVisibleRegionsDirty(false),
         mGeometryInvalid(false),
         mAnimCompositionPending(false),
@@ -258,11 +267,10 @@
         mHasPoweredOff(false),
         mNumLayers(0),
         mVrFlingerRequestsDisplay(false),
-        mMainThreadId(std::this_thread::get_id()),
-        mCreateBufferQueue(&BufferQueue::createBufferQueue),
-        mCreateNativeWindowSurface(&surfaceflinger::impl::createNativeWindowSurface) {}
+        mMainThreadId(std::this_thread::get_id()) {}
 
-SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) {
+SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory)
+      : SurfaceFlinger(factory, SkipInitialization) {
     ALOGI("SurfaceFlinger is starting");
 
     vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
@@ -299,11 +307,16 @@
     auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
     if (surfaceFlingerConfigsServiceV1_2) {
         surfaceFlingerConfigsServiceV1_2->getCompositionPreference(
-            [&](Dataspace tmpDataSpace, ui::PixelFormat tmpPixelFormat) {
-                compositionDataSpace = tmpDataSpace;
-                compositionPixelFormat = tmpPixelFormat;
-            });
+                [&](auto tmpDefaultDataspace, auto tmpDefaultPixelFormat,
+                    auto tmpWideColorGamutDataspace, auto tmpWideColorGamutPixelFormat) {
+                    defaultCompositionDataspace = tmpDefaultDataspace;
+                    defaultCompositionPixelFormat = tmpDefaultPixelFormat;
+                    wideColorGamutCompositionDataspace = tmpWideColorGamutDataspace;
+                    wideColorGamutCompositionPixelFormat = tmpWideColorGamutPixelFormat;
+                });
     }
+    mDefaultCompositionDataspace = defaultCompositionDataspace;
+    mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace;
 
     useContextPriority = getBool<ISurfaceFlingerConfigs,
                                  &ISurfaceFlingerConfigs::useContextPriority>(true);
@@ -329,13 +342,9 @@
     }
     ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation);
 
-    // Note: We create a local temporary with the real DispSync implementation
-    // type temporarily so we can initialize it with the configured values,
-    // before storing it for more generic use using the interface type.
-    auto primaryDispSync = std::make_unique<impl::DispSync>("PrimaryDispSync");
-    primaryDispSync->init(SurfaceFlinger::hasSyncFramework,
-                          SurfaceFlinger::dispSyncPresentTimeOffset);
-    mPrimaryDispSync = std::move(primaryDispSync);
+    mPrimaryDispSync =
+            getFactory().createDispSync("PrimaryDispSync", SurfaceFlinger::hasSyncFramework,
+                                        SurfaceFlinger::dispSyncPresentTimeOffset);
 
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
@@ -477,40 +486,57 @@
     sp<BBinder> token = new DisplayToken(this);
 
     Mutex::Autolock _l(mStateLock);
-    DisplayDeviceState info;
-    info.type = DisplayDevice::DISPLAY_VIRTUAL;
-    info.displayName = displayName;
-    info.isSecure = secure;
-    mCurrentState.displays.add(token, info);
-    mInterceptor->saveDisplayCreation(info);
+    // Display ID is assigned when virtual display is allocated by HWC.
+    DisplayDeviceState state;
+    state.isSecure = secure;
+    state.displayName = displayName;
+    mCurrentState.displays.add(token, state);
+    mInterceptor->saveDisplayCreation(state);
     return token;
 }
 
 void SurfaceFlinger::destroyDisplay(const sp<IBinder>& displayToken) {
     Mutex::Autolock _l(mStateLock);
 
-    ssize_t idx = mCurrentState.displays.indexOfKey(displayToken);
-    if (idx < 0) {
+    ssize_t index = mCurrentState.displays.indexOfKey(displayToken);
+    if (index < 0) {
         ALOGE("destroyDisplay: Invalid display token %p", displayToken.get());
         return;
     }
 
-    const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
-    if (!info.isVirtual()) {
+    const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
+    if (!state.isVirtual()) {
         ALOGE("destroyDisplay called for non-virtual display");
         return;
     }
-    mInterceptor->saveDisplayDeletion(info.sequenceId);
-    mCurrentState.displays.removeItemsAt(idx);
+    mInterceptor->saveDisplayDeletion(state.sequenceId);
+    mCurrentState.displays.removeItemsAt(index);
     setTransactionFlags(eDisplayTransactionNeeded);
 }
 
 sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
-    if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
-        ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
+    std::optional<DisplayId> displayId;
+
+    if (id == HWC_DISPLAY_PRIMARY) {
+        displayId = getInternalDisplayId();
+    } else if (id == HWC_DISPLAY_EXTERNAL) {
+        displayId = getExternalDisplayId();
+    }
+
+    if (!displayId) {
+        ALOGE("%s: Invalid display %d", __FUNCTION__, id);
         return nullptr;
     }
-    return mDisplayTokens[id];
+
+    return getPhysicalDisplayToken(*displayId);
+}
+
+status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const {
+    if (!outGetColorManagement) {
+        return BAD_VALUE;
+    }
+    *outGetColorManagement = useColorManagement;
+    return NO_ERROR;
 }
 
 void SurfaceFlinger::bootFinished()
@@ -585,8 +611,10 @@
 
     // start the EventThread
     if (mUseScheduler) {
-        mScheduler = std::make_unique<Scheduler>(
-                [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
+        mScheduler = getFactory().createScheduler([this](bool enabled) {
+            setVsyncEnabled(EventThread::DisplayType::Primary, enabled);
+        });
+
         mAppConnectionHandle =
                 mScheduler->createConnection("appConnection", SurfaceFlinger::vsyncPhaseOffsetNs,
                                              [this] { resyncWithRateLimit(); },
@@ -634,26 +662,21 @@
 
     // TODO(b/77156734): We need to stop casting and use HAL types when possible.
     getBE().mRenderEngine =
-        renderengine::RenderEngine::create(static_cast<int32_t>(compositionPixelFormat),
-                                           renderEngineFeature);
+            renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
+                                               renderEngineFeature);
     LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");
 
     LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
             "Starting with vr flinger active is not currently supported.");
-    getBE().mHwc.reset(
-            new HWComposer(std::make_unique<Hwc2::impl::Composer>(getBE().mHwcServiceName)));
+    getBE().mHwc = getFactory().createHWComposer(getBE().mHwcServiceName);
     getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
     // Process any initial hotplug and resulting display changes.
     processDisplayHotplugEventsLocked();
     const auto display = getDefaultDisplayDeviceLocked();
     LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback.");
-    LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getId()),
+    LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(*display->getId()),
                         "Internal display is disconnected.");
 
-    // make the default display GLContext current so that we can create textures
-    // when creating Layers (which may happens before we render something)
-    display->makeCurrent();
-
     if (useVrFlinger) {
         auto vrFlingerRequestDisplayCallback = [this](bool requestDisplay) {
             // This callback is called from the vr flinger dispatch thread. We
@@ -670,7 +693,7 @@
         };
         mVrFlinger = dvr::VrFlinger::Create(getHwComposer().getComposer(),
                                             getHwComposer()
-                                                    .getHwcDisplayId(display->getId())
+                                                    .fromPhysicalDisplayId(*display->getId())
                                                     .value_or(0),
                                             vrFlingerRequestDisplayCallback);
         if (!mVrFlinger) {
@@ -678,8 +701,8 @@
         }
     }
 
-    mEventControlThread = std::make_unique<impl::EventControlThread>(
-            [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
+    mEventControlThread = getFactory().createEventControlThread(
+            [this](bool enabled) { setVsyncEnabled(EventThread::DisplayType::Primary, enabled); });
 
     // initialize our drawing state
     mDrawingState = mCurrentState;
@@ -690,12 +713,10 @@
     getBE().mRenderEngine->primeCache();
 
     // Inform native graphics APIs whether the present timestamp is supported:
-    if (getHwComposer().hasCapability(
-            HWC2::Capability::PresentFenceIsNotReliable)) {
-        mStartPropertySetThread = new StartPropertySetThread(false);
-    } else {
-        mStartPropertySetThread = new StartPropertySetThread(true);
-    }
+
+    const bool presentFenceReliable =
+            !getHwComposer().hasCapability(HWC2::Capability::PresentFenceIsNotReliable);
+    mStartPropertySetThread = getFactory().createStartPropertySetThread(presentFenceReliable);
 
     if (mStartPropertySetThread->Start() != NO_ERROR) {
         ALOGE("Run StartPropertySetThread failed!");
@@ -707,8 +728,8 @@
     // and apply this saturation matrix on Display P3 content. Unless the risk of applying
     // such saturation matrix on Display P3 is understood fully, the API should always return
     // identify matrix.
-    mEnhancedSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(display->getId(),
-            Dataspace::SRGB_LINEAR);
+    mEnhancedSaturationMatrix =
+            getHwComposer().getDataspaceSaturationMatrix(*display->getId(), Dataspace::SRGB_LINEAR);
 
     // we will apply this on Display P3.
     if (mEnhancedSaturationMatrix != mat4()) {
@@ -795,16 +816,9 @@
         return BAD_VALUE;
     }
 
-    int32_t type = NAME_NOT_FOUND;
-    for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
-        if (displayToken == mDisplayTokens[i]) {
-            type = i;
-            break;
-        }
-    }
-
-    if (type < 0) {
-        return type;
+    const auto displayId = getPhysicalDisplayId(displayToken);
+    if (!displayId) {
+        return NAME_NOT_FOUND;
     }
 
     // TODO: Not sure if display density should handled by SF any longer
@@ -828,7 +842,7 @@
 
     ConditionalLock _l(mStateLock,
             std::this_thread::get_id() != mMainThreadId);
-    for (const auto& hwConfig : getHwComposer().getConfigs(type)) {
+    for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) {
         DisplayInfo info = DisplayInfo();
 
         float xdpi = hwConfig->getDpiX();
@@ -840,7 +854,7 @@
         info.viewportW = info.w;
         info.viewportH = info.h;
 
-        if (type == DisplayDevice::DISPLAY_PRIMARY) {
+        if (displayId == getInternalDisplayId()) {
             // The density of the device is provided by a build property
             float density = Density::getBuildDensity() / 160.0f;
             if (density == 0) {
@@ -896,7 +910,7 @@
         // All non-virtual displays are currently considered secure.
         info.secure = true;
 
-        if (type == DisplayDevice::DISPLAY_PRIMARY &&
+        if (displayId == getInternalDisplayId() &&
             primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
             std::swap(info.w, info.h);
         }
@@ -912,7 +926,6 @@
         return BAD_VALUE;
     }
 
-    // FIXME for now we always return stats for the primary display.
     if (mUseScheduler) {
         mScheduler->getDisplayStatInfo(stats);
     } else {
@@ -933,18 +946,21 @@
 }
 
 void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, int mode) {
+    if (display->isVirtual()) {
+        ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+        return;
+    }
+
     int currentMode = display->getActiveConfig();
     if (mode == currentMode) {
         return;
     }
 
-    if (display->isVirtual()) {
-        ALOGW("Trying to set config for virtual display");
-        return;
-    }
+    const auto displayId = display->getId();
+    LOG_ALWAYS_FATAL_IF(!displayId);
 
     display->setActiveConfig(mode);
-    getHwComposer().setActiveConfig(display->getDisplayType(), mode);
+    getHwComposer().setActiveConfig(*displayId, mode);
 }
 
 status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
@@ -969,29 +985,23 @@
 
     return NO_ERROR;
 }
+
 status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
                                               Vector<ColorMode>* outColorModes) {
     if (!displayToken || !outColorModes) {
         return BAD_VALUE;
     }
 
-    int32_t type = NAME_NOT_FOUND;
-    for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
-        if (displayToken == mDisplayTokens[i]) {
-            type = i;
-            break;
-        }
-    }
-
-    if (type < 0) {
-        return type;
+    const auto displayId = getPhysicalDisplayId(displayToken);
+    if (!displayId) {
+        return NAME_NOT_FOUND;
     }
 
     std::vector<ColorMode> modes;
     {
         ConditionalLock _l(mStateLock,
                 std::this_thread::get_id() != mMainThreadId);
-        modes = getHwComposer().getColorModes(type);
+        modes = getHwComposer().getColorModes(*displayId);
     }
     outColorModes->clear();
     std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes));
@@ -1008,6 +1018,11 @@
 
 void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& display, ColorMode mode,
                                                 Dataspace dataSpace, RenderIntent renderIntent) {
+    if (display->isVirtual()) {
+        ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+        return;
+    }
+
     ColorMode currentMode = display->getActiveColorMode();
     Dataspace currentDataSpace = display->getCompositionDataSpace();
     RenderIntent currentRenderIntent = display->getActiveRenderIntent();
@@ -1017,19 +1032,17 @@
         return;
     }
 
-    if (display->isVirtual()) {
-        ALOGW("Trying to set config for virtual display");
-        return;
-    }
-
     display->setActiveColorMode(mode);
     display->setCompositionDataSpace(dataSpace);
     display->setActiveRenderIntent(renderIntent);
-    getHwComposer().setActiveColorMode(display->getDisplayType(), mode, renderIntent);
 
-    ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), type=%d",
+    const auto displayId = display->getId();
+    LOG_ALWAYS_FATAL_IF(!displayId);
+    getHwComposer().setActiveColorMode(*displayId, mode, renderIntent);
+
+    ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), display=%" PRIu64,
           decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
-          renderIntent, display->getDisplayType());
+          renderIntent, *displayId);
 }
 
 status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
@@ -1156,10 +1169,14 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getCompositionPreference(Dataspace* outDataSpace,
-                                                  ui::PixelFormat* outPixelFormat) const {
-    *outDataSpace = compositionDataSpace;
-    *outPixelFormat = compositionPixelFormat;
+status_t SurfaceFlinger::getCompositionPreference(
+        Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
+        Dataspace* outWideColorGamutDataspace,
+        ui::PixelFormat* outWideColorGamutPixelFormat) const {
+    *outDataspace = mDefaultCompositionDataspace;
+    *outPixelFormat = defaultCompositionPixelFormat;
+    *outWideColorGamutDataspace = mWideColorGamutCompositionDataspace;
+    *outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat;
     return NO_ERROR;
 }
 
@@ -1235,18 +1252,22 @@
 
     if (makeAvailable) {
         mHWVsyncAvailable = true;
+        // TODO(b/113612090): This is silly, but necessary evil until we turn on the flag for good.
+        if (mUseScheduler) {
+            mScheduler->makeHWSyncAvailable(true);
+        }
     } else if (!mHWVsyncAvailable) {
         // Hardware vsync is not currently available, so abort the resync
         // attempt for now
         return;
     }
 
-    const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
-    if (!getHwComposer().isConnected(displayId)) {
+    const auto displayId = getInternalDisplayId();
+    if (!displayId || !getHwComposer().isConnected(*displayId)) {
         return;
     }
 
-    const auto activeConfig = getHwComposer().getActiveConfig(displayId);
+    const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
     const nsecs_t period = activeConfig->getVsyncPeriod();
 
     if (mUseScheduler) {
@@ -1297,12 +1318,11 @@
         return;
     }
 
-    int32_t type;
-    if (!getBE().mHwc->onVsync(hwcDisplayId, timestamp, &type)) {
+    if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) {
         return;
     }
 
-    if (type != DisplayDevice::DISPLAY_PRIMARY) {
+    if (hwcDisplayId != getHwComposer().getInternalHwcDisplayId()) {
         // For now, we don't do anything with external display vsyncs.
         return;
     }
@@ -1365,11 +1385,13 @@
     repaintEverything();
 }
 
-void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
+void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) {
     ATRACE_CALL();
     Mutex::Autolock lock(mStateLock);
-    getHwComposer().setVsyncEnabled(disp,
-            enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+    if (const auto displayId = getInternalDisplayId()) {
+        getHwComposer().setVsyncEnabled(*displayId,
+                                        enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+    }
 }
 
 // Note: it is assumed the caller holds |mStateLock| when this is called
@@ -1384,7 +1406,6 @@
     // mCurrentState and mDrawingState and re-apply all changes when we make the
     // transition.
     mDrawingState.displays.clear();
-    getRenderEngine().resetCurrentSurface();
     mDisplays.clear();
 }
 
@@ -1420,8 +1441,8 @@
 
     resetDisplayState();
     getBE().mHwc.reset(); // Delete the current instance before creating the new one
-    getBE().mHwc.reset(new HWComposer(std::make_unique<Hwc2::impl::Composer>(
-            vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName)));
+    getBE().mHwc = getFactory().createHWComposer(
+            vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName);
     getBE().mHwc->registerCallback(this, ++getBE().mComposerSequenceId);
 
     LOG_ALWAYS_FATAL_IF(!getBE().mHwc->getComposer()->isRemote(),
@@ -1440,7 +1461,7 @@
     setPowerModeInternal(display, currentDisplayPowerMode, /*stateLockHeld*/ true);
 
     // Reset the timing values to account for the period of the swapped in HWC
-    const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+    const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
     const nsecs_t period = activeConfig->getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
 
@@ -1558,8 +1579,7 @@
 
     getBE().mEndOfFrameCompositionInfo = std::move(getBE().mCompositionInfo);
     for (const auto& [token, display] : mDisplays) {
-        const auto displayId = display->getId();
-        for (auto& compositionInfo : getBE().mEndOfFrameCompositionInfo[displayId]) {
+        for (auto& compositionInfo : getBE().mEndOfFrameCompositionInfo[token]) {
             compositionInfo.hwc.hwcLayer = nullptr;
         }
     }
@@ -1582,24 +1602,25 @@
         mGeometryInvalid = false;
         for (const auto& [token, display] : mDisplays) {
             const auto displayId = display->getId();
-            if (displayId >= 0) {
-                const Vector<sp<Layer>>& currentLayers(
-                        display->getVisibleLayersSortedByZ());
-                for (size_t i = 0; i < currentLayers.size(); i++) {
-                    const auto& layer = currentLayers[i];
+            if (!displayId) {
+                continue;
+            }
 
-                    if (!layer->hasHwcLayer(displayId)) {
-                        if (!layer->createHwcLayer(getBE().mHwc.get(), displayId)) {
-                            layer->forceClientComposition(displayId);
-                            continue;
-                        }
-                    }
+            const Vector<sp<Layer>>& currentLayers = display->getVisibleLayersSortedByZ();
+            for (size_t i = 0; i < currentLayers.size(); i++) {
+                const auto& layer = currentLayers[i];
 
-                    layer->setGeometry(display, i);
-                    if (mDebugDisableHWC || mDebugRegion) {
-                        layer->forceClientComposition(displayId);
+                if (!layer->hasHwcLayer(*displayId)) {
+                    if (!layer->createHwcLayer(&getHwComposer(), *displayId)) {
+                        layer->forceClientComposition(*displayId);
+                        continue;
                     }
                 }
+
+                layer->setGeometry(display, i);
+                if (mDebugDisableHWC || mDebugRegion) {
+                    layer->forceClientComposition(*displayId);
+                }
             }
         }
     }
@@ -1607,41 +1628,43 @@
     // Set the per-frame data
     for (const auto& [token, display] : mDisplays) {
         const auto displayId = display->getId();
-        if (displayId < 0) {
+        if (!displayId) {
             continue;
         }
 
         if (mDrawingState.colorMatrixChanged) {
             display->setColorTransform(mDrawingState.colorMatrix);
-            status_t result = getBE().mHwc->setColorTransform(displayId, mDrawingState.colorMatrix);
-            ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
-                    "display %d: %d", displayId, result);
+            status_t result =
+                    getHwComposer().setColorTransform(*displayId, mDrawingState.colorMatrix);
+            ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display %" PRIu64 ": %d",
+                     *displayId, result);
         }
         for (auto& layer : display->getVisibleLayersSortedByZ()) {
             if (layer->isHdrY410()) {
-                layer->forceClientComposition(displayId);
+                layer->forceClientComposition(*displayId);
             } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
                         layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
                     !display->hasHDR10Support()) {
-                layer->forceClientComposition(displayId);
+                layer->forceClientComposition(*displayId);
             } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
                         layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
                     !display->hasHLGSupport()) {
-                layer->forceClientComposition(displayId);
+                layer->forceClientComposition(*displayId);
             }
 
             // TODO(b/111562338) remove when composer 2.3 is shipped.
             if (layer->hasColorTransform()) {
-                layer->forceClientComposition(displayId);
+                layer->forceClientComposition(*displayId);
             }
 
-            if (layer->getForceClientComposition(displayId)) {
+            if (layer->getForceClientComposition(*displayId)) {
                 ALOGV("[%s] Requesting Client composition", layer->getName().string());
-                layer->setCompositionType(displayId, HWC2::Composition::Client);
+                layer->setCompositionType(*displayId, HWC2::Composition::Client);
                 continue;
             }
 
-            layer->setPerFrameData(display);
+            layer->setPerFrameData(*displayId, display->getTransform(), display->getViewport(),
+                                   display->getSupportedPerFrameMetadata());
         }
 
         if (useColorManagement) {
@@ -1656,16 +1679,20 @@
     mDrawingState.colorMatrixChanged = false;
 
     for (const auto& [token, display] : mDisplays) {
-        const auto displayId = display->getId();
-        getBE().mCompositionInfo[displayId].clear();
+        getBE().mCompositionInfo[token].clear();
+
         for (auto& layer : display->getVisibleLayersSortedByZ()) {
-            auto displayId = display->getId();
+            const auto displayId = display->getId();
             layer->getBE().compositionInfo.compositionType = layer->getCompositionType(displayId);
-            if (!layer->setHwcLayer(displayId)) {
-                ALOGV("Need to create HWCLayer for %s", layer->getName().string());
+
+            if (displayId) {
+                if (!layer->setHwcLayer(*displayId)) {
+                    ALOGV("Need to create HWCLayer for %s", layer->getName().string());
+                }
+                layer->getBE().compositionInfo.hwc.displayId = *displayId;
             }
-            layer->getBE().compositionInfo.hwc.displayId = displayId;
-            getBE().mCompositionInfo[displayId].push_back(layer->getBE().compositionInfo);
+
+            getBE().mCompositionInfo[token].push_back(layer->getBE().compositionInfo);
             layer->getBE().compositionInfo.hwc.hwcLayer = nullptr;
         }
     }
@@ -1673,7 +1700,6 @@
 
 void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything)
 {
-    const auto displayId = display->getId();
     // is debugging enabled
     if (CC_LIKELY(!mDebugRegion))
         return;
@@ -1689,7 +1715,7 @@
             auto& engine(getRenderEngine());
             engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1);
 
-            display->swapBuffers(getHwComposer());
+            display->queueBuffer(getHwComposer());
         }
     }
 
@@ -1699,14 +1725,7 @@
         usleep(mDebugRegion * 1000);
     }
 
-    if (display->isPoweredOn()) {
-        status_t result = display->prepareFrame(
-                *getBE().mHwc, getBE().mCompositionInfo[displayId]);
-        ALOGE_IF(result != NO_ERROR,
-                 "prepareFrame for display %d failed:"
-                 " %d (%s)",
-                 display->getId(), result, strerror(-result));
-    }
+    prepareFrame(display);
 }
 
 void SurfaceFlinger::doTracing(const char* where) {
@@ -1832,7 +1851,7 @@
 
     getBE().mDisplayTimeline.updateSignalTimes();
     mPreviousPresentFence =
-            display ? getHwComposer().getPresentFence(display->getId()) : Fence::NO_FENCE;
+            display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE;
     auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
     getBE().mDisplayTimeline.push(presentFenceTime);
 
@@ -1855,8 +1874,8 @@
     }
 
     mDrawingState.traverseInZOrder([&](Layer* layer) {
-        bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
-                presentFenceTime, compositorTiming);
+        bool frameLatched = layer->onPostComposition(display->getId(), glCompositionDoneFenceTime,
+                                                     presentFenceTime, compositorTiming);
         if (frameLatched) {
             recordBufferingStats(layer->getName().string(),
                     layer->getOccupancyHistory(false));
@@ -1876,7 +1895,7 @@
     }
 
     if (!hasSyncFramework) {
-        if (display && getHwComposer().isConnected(display->getId()) && display->isPoweredOn()) {
+        if (display && getHwComposer().isConnected(*display->getId()) && display->isPoweredOn()) {
             if (mUseScheduler) {
                 mScheduler->enableHardwareVsync();
             } else {
@@ -1891,10 +1910,10 @@
         if (presentFenceTime->isValid()) {
             mAnimFrameTracker.setActualPresentFence(
                     std::move(presentFenceTime));
-        } else if (display && getHwComposer().isConnected(display->getId())) {
+        } else if (display && getHwComposer().isConnected(*display->getId())) {
             // The HWC doesn't support present fences, so use the refresh
             // timestamp instead.
-            const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(display->getId());
+            const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(*display->getId());
             mAnimFrameTracker.setActualPresentTime(presentTime);
         }
         mAnimFrameTracker.advanceFrame();
@@ -1907,8 +1926,7 @@
 
     mTimeStats.setPresentFenceGlobal(presentFenceTime);
 
-    if (display && getHwComposer().isConnected(display->getId()) &&
-        display->getPowerMode() == HWC_POWER_MODE_OFF) {
+    if (display && getHwComposer().isConnected(*display->getId()) && !display->isPoweredOn()) {
         return;
     }
 
@@ -1937,6 +1955,9 @@
             ATRACE_INT("TexturePoolSize", mTexturePool.size());
         }
     }
+
+    mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
+    mTransactionCompletedThread.sendCallbacks();
 }
 
 void SurfaceFlinger::rebuildLayerStacks() {
@@ -1962,6 +1983,7 @@
 
                 mDrawingState.traverseInZOrder([&](Layer* layer) {
                     bool hwcLayerDestroyed = false;
+                    const auto displayId = display->getId();
                     if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
                         Region drawRegion(tr.transform(
                                 layer->visibleNonTransparentRegion));
@@ -1971,13 +1993,13 @@
                         } else {
                             // Clear out the HWC layer if this layer was
                             // previously visible, but no longer is
-                            hwcLayerDestroyed = layer->destroyHwcLayer(display->getId());
+                            hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
                         }
                     } else {
                         // WM changes display->layerStack upon sleep/awake.
                         // Here we make sure we delete the HWC layers even if
                         // WM changed their layer stack.
-                        hwcLayerDestroyed = layer->destroyHwcLayer(display->getId());
+                        hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
                     }
 
                     // If a layer is not going to get a release fence because
@@ -2102,12 +2124,11 @@
     //   emit any black frames until a layer is added to the layer stack.
     bool mustRecompose = dirty && !(empty && wasEmpty);
 
-    ALOGV_IF(display->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
-            "id[%d]: %s composition (%sdirty %sempty %swasEmpty)", display->getId(),
-            mustRecompose ? "doing" : "skipping",
-            dirty ? "+" : "-",
-            empty ? "+" : "-",
-            wasEmpty ? "+" : "-");
+    const char flagPrefix[] = {'-', '+'};
+    static_cast<void>(flagPrefix);
+    ALOGV_IF(display->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
+             __FUNCTION__, mustRecompose ? "doing" : "skipping", display->getDebugName().c_str(),
+             flagPrefix[dirty], flagPrefix[empty], flagPrefix[wasEmpty]);
 
     display->beginFrame(mustRecompose);
 
@@ -2118,17 +2139,14 @@
 
 void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& display)
 {
-    const auto displayId = display->getId();
     if (!display->isPoweredOn()) {
         return;
     }
 
-    status_t result = display->prepareFrame(
-            *getBE().mHwc, getBE().mCompositionInfo[displayId]);
-    ALOGE_IF(result != NO_ERROR,
-             "prepareFrame for display %d failed:"
-             " %d (%s)",
-             display->getId(), result, strerror(-result));
+    status_t result = display->prepareFrame(getHwComposer(),
+                                            getBE().mCompositionInfo[display->getDisplayToken()]);
+    ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
+             display->getDebugName().c_str(), result, strerror(-result));
 }
 
 void SurfaceFlinger::doComposition(const sp<DisplayDevice>& display, bool repaintEverything) {
@@ -2151,8 +2169,9 @@
 void SurfaceFlinger::postFrame()
 {
     // |mStateLock| not needed as we are on the main thread
-    if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
-        uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
+    const auto display = getDefaultDisplayDeviceLocked();
+    if (display && getHwComposer().isConnected(*display->getId())) {
+        uint32_t flipCount = display->getPageFlipCount();
         if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
             logFrameStats();
         }
@@ -2168,20 +2187,19 @@
 
     if (display->isPoweredOn()) {
         const auto displayId = display->getId();
-        if (displayId >= 0) {
-            getBE().mHwc->presentAndGetReleaseFences(displayId);
+        if (displayId) {
+            getHwComposer().presentAndGetReleaseFences(*displayId);
         }
-        display->onSwapBuffersCompleted();
-        display->makeCurrent();
+        display->onPresentDisplayCompleted();
         for (auto& layer : display->getVisibleLayersSortedByZ()) {
             sp<Fence> releaseFence = Fence::NO_FENCE;
 
             // The layer buffer from the previous frame (if any) is released
             // by HWC only when the release fence from this frame (if any) is
             // signaled.  Always get the release fence from HWC first.
-            auto hwcLayer = layer->getHwcLayer(displayId);
-            if (displayId >= 0) {
-                releaseFence = getBE().mHwc->getLayerReleaseFence(displayId, hwcLayer);
+            if (displayId && layer->hasHwcLayer(*displayId)) {
+                releaseFence = getHwComposer().getLayerReleaseFence(*displayId,
+                                                                    layer->getHwcLayer(*displayId));
             }
 
             // If the layer was client composited in the previous frame, we
@@ -2201,14 +2219,15 @@
         // display->getVisibleLayersSortedByZ.  The best we can do is to
         // supply them with the present fence.
         if (!display->getLayersNeedingFences().isEmpty()) {
-            sp<Fence> presentFence = getBE().mHwc->getPresentFence(displayId);
+            sp<Fence> presentFence =
+                    displayId ? getBE().mHwc->getPresentFence(*displayId) : Fence::NO_FENCE;
             for (auto& layer : display->getLayersNeedingFences()) {
                 layer->getBE().onLayerDisplayed(presentFence);
             }
         }
 
-        if (displayId >= 0) {
-            getBE().mHwc->clearReleaseFences(displayId);
+        if (displayId) {
+            getHwComposer().clearReleaseFences(*displayId);
         }
     }
 }
@@ -2243,72 +2262,36 @@
     // here the transaction has been committed
 }
 
-DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t hwcDisplayId,
-                                                                HWC2::Connection connection) const {
-    // Figure out whether the event is for the primary display or an
-    // external display by matching the Hwc display id against one for a
-    // connected display. If we did not find a match, we then check what
-    // displays are not already connected to determine the type. If we don't
-    // have a connected primary display, we assume the new display is meant to
-    // be the primary display, and then if we don't have an external display,
-    // we assume it is that.
-    const auto primaryHwcDisplayId = getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_PRIMARY);
-    const auto externalHwcDisplayId =
-            getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_EXTERNAL);
-    if (primaryHwcDisplayId && primaryHwcDisplayId == hwcDisplayId) {
-        return DisplayDevice::DISPLAY_PRIMARY;
-    } else if (externalHwcDisplayId && externalHwcDisplayId == hwcDisplayId) {
-        return DisplayDevice::DISPLAY_EXTERNAL;
-    } else if (connection == HWC2::Connection::Connected && !primaryHwcDisplayId) {
-        return DisplayDevice::DISPLAY_PRIMARY;
-    } else if (connection == HWC2::Connection::Connected && !externalHwcDisplayId) {
-        return DisplayDevice::DISPLAY_EXTERNAL;
-    }
-
-    return DisplayDevice::DISPLAY_ID_INVALID;
-}
-
 void SurfaceFlinger::processDisplayHotplugEventsLocked() {
     for (const auto& event : mPendingHotplugEvents) {
-        auto displayType = determineDisplayType(event.hwcDisplayId, event.connection);
-        if (displayType == DisplayDevice::DISPLAY_ID_INVALID) {
-            ALOGW("Unable to determine the display type for display %" PRIu64, event.hwcDisplayId);
-            continue;
-        }
+        const std::optional<DisplayIdentificationInfo> info =
+                getHwComposer().onHotplug(event.hwcDisplayId, event.connection);
 
-        if (getBE().mHwc->isUsingVrComposer() && displayType == DisplayDevice::DISPLAY_EXTERNAL) {
-            ALOGE("External displays are not supported by the vr hardware composer.");
+        if (!info) {
             continue;
         }
 
-        const auto displayId =
-                getBE().mHwc->onHotplug(event.hwcDisplayId, displayType, event.connection);
-        if (displayId) {
-            ALOGV("Display %" PRIu64 " has stable ID %" PRIu64, event.hwcDisplayId, *displayId);
-        }
-
         if (event.connection == HWC2::Connection::Connected) {
-            if (!mDisplayTokens[displayType].get()) {
-                ALOGV("Creating built in display %d", displayType);
-                mDisplayTokens[displayType] = new BBinder();
-                DisplayDeviceState info;
-                info.type = displayType;
-                info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
-                        "Built-in Screen" : "External Screen";
-                info.isSecure = true; // All physical displays are currently considered secure.
-                mCurrentState.displays.add(mDisplayTokens[displayType], info);
-                mInterceptor->saveDisplayCreation(info);
+            if (!mPhysicalDisplayTokens.count(info->id)) {
+                ALOGV("Creating display %" PRIu64, info->id);
+                mPhysicalDisplayTokens[info->id] = new BBinder();
+                DisplayDeviceState state;
+                state.displayId = info->id;
+                state.isSecure = true; // All physical displays are currently considered secure.
+                state.displayName = info->name;
+                mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
+                mInterceptor->saveDisplayCreation(state);
             }
         } else {
-            ALOGV("Removing built in display %d", displayType);
+            ALOGV("Removing display %" PRIu64, info->id);
 
-            ssize_t idx = mCurrentState.displays.indexOfKey(mDisplayTokens[displayType]);
-            if (idx >= 0) {
-                const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
-                mInterceptor->saveDisplayDeletion(info.sequenceId);
-                mCurrentState.displays.removeItemsAt(idx);
+            ssize_t index = mCurrentState.displays.indexOfKey(mPhysicalDisplayTokens[info->id]);
+            if (index >= 0) {
+                const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
+                mInterceptor->saveDisplayDeletion(state.sequenceId);
+                mCurrentState.displays.removeItemsAt(index);
             }
-            mDisplayTokens[displayType].clear();
+            mPhysicalDisplayTokens.erase(info->id);
         }
 
         processDisplayChangesLocked();
@@ -2318,67 +2301,56 @@
 }
 
 sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
-        const wp<IBinder>& displayToken, int32_t displayId, const DisplayDeviceState& state,
-        const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
-    DisplayDeviceCreationArgs creationArgs(this, displayToken, state.type, displayId);
+        const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
+        const DisplayDeviceState& state, const sp<DisplaySurface>& dispSurface,
+        const sp<IGraphicBufferProducer>& producer) {
+    DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
+    creationArgs.isVirtual = state.isVirtual();
     creationArgs.isSecure = state.isSecure;
     creationArgs.displaySurface = dispSurface;
     creationArgs.hasWideColorGamut = false;
     creationArgs.supportedPerFrameMetadata = 0;
 
-    if (useColorManagement && displayId >= 0) {
-        std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
+    const bool isInternalDisplay = displayId && displayId == getInternalDisplayId();
+    creationArgs.isPrimary = isInternalDisplay;
+
+    if (useColorManagement && displayId) {
+        std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
         for (ColorMode colorMode : modes) {
             if (isWideColorMode(colorMode)) {
                 creationArgs.hasWideColorGamut = true;
             }
 
             std::vector<RenderIntent> renderIntents =
-                    getHwComposer().getRenderIntents(displayId, colorMode);
+                    getHwComposer().getRenderIntents(*displayId, colorMode);
             creationArgs.hwcColorModes.emplace(colorMode, renderIntents);
         }
     }
 
-    if (displayId >= 0) {
-        getHwComposer().getHdrCapabilities(displayId, &creationArgs.hdrCapabilities);
+    if (displayId) {
+        getHwComposer().getHdrCapabilities(*displayId, &creationArgs.hdrCapabilities);
         creationArgs.supportedPerFrameMetadata =
-                getHwComposer().getSupportedPerFrameMetadata(displayId);
+                getHwComposer().getSupportedPerFrameMetadata(*displayId);
     }
 
-    auto nativeWindowSurface = mCreateNativeWindowSurface(producer);
+    auto nativeWindowSurface = getFactory().createNativeWindowSurface(producer);
     auto nativeWindow = nativeWindowSurface->getNativeWindow();
     creationArgs.nativeWindow = nativeWindow;
 
-    /*
-     * Create our display's surface
-     */
-    std::unique_ptr<renderengine::Surface> renderSurface = getRenderEngine().createSurface();
-    renderSurface->setCritical(state.type == DisplayDevice::DISPLAY_PRIMARY);
-    renderSurface->setAsync(state.isVirtual());
-    renderSurface->setNativeWindow(nativeWindow.get());
-    creationArgs.displayWidth = renderSurface->getWidth();
-    creationArgs.displayHeight = renderSurface->getHeight();
-    creationArgs.renderSurface = std::move(renderSurface);
-
     // Make sure that composition can never be stalled by a virtual display
     // consumer that isn't processing buffers fast enough. We have to do this
-    // in two places:
-    // * Here, in case the display is composed entirely by HWC.
-    // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
-    //   window's swap interval in eglMakeCurrent, so they'll override the
-    //   interval we set here.
+    // here, in case the display is composed entirely by HWC.
     if (state.isVirtual()) {
         nativeWindow->setSwapInterval(nativeWindow.get(), 0);
     }
 
-    creationArgs.displayInstallOrientation = state.type == DisplayDevice::DISPLAY_PRIMARY
-            ? primaryDisplayOrientation
-            : DisplayState::eOrientationDefault;
+    creationArgs.displayInstallOrientation =
+            isInternalDisplay ? primaryDisplayOrientation : DisplayState::eOrientationDefault;
 
     // virtual displays are always considered enabled
     creationArgs.initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
 
-    sp<DisplayDevice> display = new DisplayDevice(std::move(creationArgs));
+    sp<DisplayDevice> display = getFactory().createDisplayDevice(std::move(creationArgs));
 
     if (maxFrameBufferAcquiredBuffers >= 3) {
         nativeWindowSurface->preallocateBuffers();
@@ -2392,9 +2364,11 @@
     }
     setActiveColorModeInternal(display, defaultColorMode, defaultDataSpace,
                                RenderIntent::COLORIMETRIC);
-    if (state.type < DisplayDevice::DISPLAY_VIRTUAL) {
-        display->setActiveConfig(getHwComposer().getActiveConfigIndex(state.type));
+    if (!state.isVirtual()) {
+        LOG_ALWAYS_FATAL_IF(!displayId);
+        display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
     }
+
     display->setLayerStack(state.layerStack);
     display->setProjection(state.orientation, state.viewport, state.frame);
     display->setDisplayName(state.displayName);
@@ -2420,24 +2394,22 @@
         for (size_t i = 0; i < dc;) {
             const ssize_t j = curr.indexOfKey(draw.keyAt(i));
             if (j < 0) {
+                // Save display IDs before disconnecting.
+                const auto internalDisplayId = getInternalDisplayId();
+                const auto externalDisplayId = getExternalDisplayId();
+
                 // in drawing state but not in current state
-                // Call makeCurrent() on the primary display so we can
-                // be sure that nothing associated with this display
-                // is current.
-                if (const auto defaultDisplay = getDefaultDisplayDeviceLocked()) {
-                    defaultDisplay->makeCurrent();
-                }
                 if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
                     display->disconnect(getHwComposer());
                 }
-                if (draw[i].type == DisplayDevice::DISPLAY_PRIMARY) {
+                if (internalDisplayId && internalDisplayId == draw[i].displayId) {
                     if (mUseScheduler) {
                         mScheduler->hotplugReceived(mAppConnectionHandle,
                                                     EventThread::DisplayType::Primary, false);
                     } else {
                         mEventThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
                     }
-                } else if (draw[i].type == DisplayDevice::DISPLAY_EXTERNAL) {
+                } else if (externalDisplayId && externalDisplayId == draw[i].displayId) {
                     if (mUseScheduler) {
                         mScheduler->hotplugReceived(mAppConnectionHandle,
                                                     EventThread::DisplayType::External, false);
@@ -2493,16 +2465,16 @@
                 sp<IGraphicBufferProducer> producer;
                 sp<IGraphicBufferProducer> bqProducer;
                 sp<IGraphicBufferConsumer> bqConsumer;
-                mCreateBufferQueue(&bqProducer, &bqConsumer, false);
+                getFactory().createBufferQueue(&bqProducer, &bqConsumer, false);
 
-                int32_t displayId = -1;
+                std::optional<DisplayId> displayId;
                 if (state.isVirtual()) {
                     // Virtual displays without a surface are dormant:
                     // they have external state (layer stack, projection,
                     // etc.) but no internal state (i.e. a DisplayDevice).
                     if (state.surface != nullptr) {
                         // Allow VR composer to use virtual displays.
-                        if (mUseHwcVirtualDisplays || getBE().mHwc->isUsingVrComposer()) {
+                        if (mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer()) {
                             int width = 0;
                             int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
                             ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
@@ -2514,14 +2486,14 @@
                             ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
                             auto format = static_cast<ui::PixelFormat>(intFormat);
 
-                            getBE().mHwc->allocateVirtualDisplay(width, height, &format,
-                                                                 &displayId);
+                            displayId =
+                                    getHwComposer().allocateVirtualDisplay(width, height, &format);
                         }
 
                         // TODO: Plumb requested format back up to consumer
 
                         sp<VirtualDisplaySurface> vds =
-                                new VirtualDisplaySurface(*getBE().mHwc, displayId, state.surface,
+                                new VirtualDisplaySurface(getHwComposer(), displayId, state.surface,
                                                           bqProducer, bqConsumer,
                                                           state.displayName);
 
@@ -2534,8 +2506,9 @@
                              "surface is provided (%p), ignoring it",
                              state.surface.get());
 
-                    displayId = state.type;
-                    dispSurface = new FramebufferSurface(*getBE().mHwc, displayId, bqConsumer);
+                    displayId = state.displayId;
+                    LOG_ALWAYS_FATAL_IF(!displayId);
+                    dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
                     producer = bqProducer;
                 }
 
@@ -2545,7 +2518,9 @@
                                       setupNewDisplayDeviceInternal(displayToken, displayId, state,
                                                                     dispSurface, producer));
                     if (!state.isVirtual()) {
-                        if (state.type == DisplayDevice::DISPLAY_PRIMARY) {
+                        LOG_ALWAYS_FATAL_IF(!displayId);
+
+                        if (displayId == getInternalDisplayId()) {
                             if (mUseScheduler) {
                                 mScheduler->hotplugReceived(mAppConnectionHandle,
                                                             EventThread::DisplayType::Primary,
@@ -2554,7 +2529,7 @@
                                 mEventThread->onHotplugReceived(EventThread::DisplayType::Primary,
                                                                 true);
                             }
-                        } else if (state.type == DisplayDevice::DISPLAY_EXTERNAL) {
+                        } else if (displayId == getExternalDisplayId()) {
                             if (mUseScheduler) {
                                 mScheduler->hotplugReceived(mAppConnectionHandle,
                                                             EventThread::DisplayType::External,
@@ -2708,7 +2683,7 @@
 void SurfaceFlinger::updateCursorAsync()
 {
     for (const auto& [token, display] : mDisplays) {
-        if (display->getId() < 0) {
+        if (!display->getId()) {
             continue;
         }
 
@@ -2725,7 +2700,19 @@
         for (const auto& l : mLayersPendingRemoval) {
             recordBufferingStats(l->getName().string(),
                     l->getOccupancyHistory(true));
-            l->onRemoved();
+
+            // We need to release the HWC layers when the Layer is removed
+            // from the current state otherwise the HWC layer just continues
+            // showing at its last configured state until we eventually
+            // abandon the buffer queue.
+            if (l->isRemovedFromCurrentState()) {
+                l->destroyAllHwcLayers();
+                // destroyAllHwcLayers traverses to children, but releasePendingBuffer
+                // doesn't in other scenarios. So we have to traverse explicitly here.
+                l->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* child) {
+                    child->releasePendingBuffer(systemTime());
+                });
+            }
         }
         mLayersPendingRemoval.clear();
     }
@@ -2962,7 +2949,7 @@
     mGeometryInvalid = true;
 }
 
-void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& display,
+void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& display,
                                           const Region& inDirtyRegion) {
     // We only need to actually compose the display if:
     // 1) It is being handled by hardware composer, which may need this to
@@ -2978,10 +2965,10 @@
     if (!doComposeSurfaces(display)) return;
 
     // swap buffers (presentation)
-    display->swapBuffers(getHwComposer());
+    display->queueBuffer(getHwComposer());
 }
 
-bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& display) {
+bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& display) {
     ALOGV("doComposeSurfaces");
 
     const Region bounds(display->bounds());
@@ -2994,9 +2981,31 @@
     bool applyColorMatrix = false;
     bool needsEnhancedColorMatrix = false;
 
+    // Framebuffer will live in this scope for GPU composition.
+    std::unique_ptr<renderengine::BindNativeBufferAsFramebuffer> fbo;
+
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
+        sp<GraphicBuffer> buf = display->dequeueBuffer();
+
+        if (buf == nullptr) {
+            ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
+                  "client composition for this frame",
+                  display->getDisplayName().c_str());
+            return false;
+        }
+
+        // Bind the framebuffer in this scope.
+        fbo = std::make_unique<renderengine::BindNativeBufferAsFramebuffer>(getRenderEngine(),
+                                                                            buf->getNativeBuffer());
+
+        if (fbo->getStatus() != NO_ERROR) {
+            ALOGW("Binding buffer for display [%s] failed with status: %d",
+                  display->getDisplayName().c_str(), fbo->getStatus());
+            return false;
+        }
+
         Dataspace outputDataspace = Dataspace::UNKNOWN;
         if (display->hasWideColorGamut()) {
             outputDataspace = display->getCompositionDataSpace();
@@ -3025,18 +3034,7 @@
             colorMatrix *= mEnhancedSaturationMatrix;
         }
 
-        if (!display->makeCurrent()) {
-            ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
-                  display->getDisplayName().c_str());
-            getRenderEngine().resetCurrentSurface();
-
-            // |mStateLock| not needed as we are on the main thread
-            const auto defaultDisplay = getDefaultDisplayDeviceLocked();
-            if (!defaultDisplay || !defaultDisplay->makeCurrent()) {
-                ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
-            }
-            return false;
-        }
+        display->setViewportAndProjection();
 
         // Never touch the framebuffer if we don't have any framebuffer layers
         if (hasDeviceComposition) {
@@ -3092,8 +3090,9 @@
                 case HWC2::Composition::Device:
                 case HWC2::Composition::Sideband:
                 case HWC2::Composition::SolidColor: {
+                    LOG_ALWAYS_FATAL_IF(!displayId);
                     const Layer::State& state(layer->getDrawingState());
-                    if (layer->getClearClientTarget(displayId) && !firstLayer &&
+                    if (layer->getClearClientTarget(*displayId) && !firstLayer &&
                         layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
                         hasClientComposition) {
                         // never clear the very first layer since we're
@@ -3128,11 +3127,15 @@
         firstLayer = false;
     }
 
-    // Clear color transform matrix at the end of the frame.
-    getRenderEngine().setColorTransform(mat4());
-
-    // disable scissor at the end of the frame
-    getBE().mRenderEngine->disableScissor();
+    // Perform some cleanup steps if we used client composition.
+    if (hasClientComposition) {
+        getRenderEngine().setColorTransform(mat4());
+        getBE().mRenderEngine->disableScissor();
+        display->finishBuffer();
+        // Clear out error flags here so that we don't wait until next
+        // composition to log.
+        getRenderEngine().checkErrors();
+    }
     return true;
 }
 
@@ -3158,7 +3161,7 @@
         if (parent == nullptr) {
             mCurrentState.layersSortedByZ.add(lbc);
         } else {
-            if (parent->isPendingRemoval()) {
+            if (parent->isRemovedFromCurrentState()) {
                 ALOGE("addClientLayer called with a removed parent");
                 return NAME_NOT_FOUND;
             }
@@ -3174,7 +3177,6 @@
                                 mMaxGraphicBufferProducerListSize, mNumLayers);
         }
         mLayersAdded = true;
-        mNumLayers++;
     }
 
     // attach this layer to the client
@@ -3188,52 +3190,22 @@
     return removeLayerLocked(mStateLock, layer, topLevelOnly);
 }
 
-status_t SurfaceFlinger::removeLayerLocked(const Mutex&, const sp<Layer>& layer,
+status_t SurfaceFlinger::removeLayerLocked(const Mutex& lock, const sp<Layer>& layer,
                                            bool topLevelOnly) {
-    if (layer->isPendingRemoval()) {
-        return NO_ERROR;
-    }
-
     const auto& p = layer->getParent();
     ssize_t index;
     if (p != nullptr) {
         if (topLevelOnly) {
             return NO_ERROR;
         }
-
-        sp<Layer> ancestor = p;
-        while (ancestor->getParent() != nullptr) {
-            ancestor = ancestor->getParent();
-        }
-        if (mCurrentState.layersSortedByZ.indexOf(ancestor) < 0) {
-            ALOGE("removeLayer called with a layer whose parent has been removed");
-            return NAME_NOT_FOUND;
-        }
-
         index = p->removeChild(layer);
     } else {
         index = mCurrentState.layersSortedByZ.remove(layer);
     }
 
-    // As a matter of normal operation, the LayerCleaner will produce a second
-    // attempt to remove the surface. The Layer will be kept alive in mDrawingState
-    // so we will succeed in promoting it, but it's already been removed
-    // from mCurrentState. As long as we can find it in mDrawingState we have no problem
-    // otherwise something has gone wrong and we are leaking the layer.
-    if (index < 0 && mDrawingState.layersSortedByZ.indexOf(layer) < 0) {
-        ALOGE("Failed to find layer (%s) in layer parent (%s).",
-                layer->getName().string(),
-                (p != nullptr) ? p->getName().string() : "no-parent");
-        return BAD_VALUE;
-    } else if (index < 0) {
-        return NO_ERROR;
-    }
-
     layer->onRemovedFromCurrentState();
-    mLayersPendingRemoval.add(layer);
-    mLayersRemoved = true;
-    mNumLayers -= 1 + layer->getChildrenCount();
-    setTransactionFlags(eTransactionNeeded);
+
+    markLayerPendingRemovalLocked(lock, layer);
     return NO_ERROR;
 }
 
@@ -3314,9 +3286,15 @@
         transactionFlags |= setDisplayStateLocked(display);
     }
 
+    uint32_t clientStateFlags = 0;
     for (const ComposerState& state : states) {
-        transactionFlags |= setClientStateLocked(state);
+        clientStateFlags |= setClientStateLocked(state);
     }
+    // If the state doesn't require a traversal and there are callbacks, send them now
+    if (!(clientStateFlags & eTraversalNeeded)) {
+        mTransactionCompletedThread.sendCallbacks();
+    }
+    transactionFlags |= clientStateFlags;
 
     // Iterate through all layers again to determine if any need to be destroyed. Marking layers
     // as destroyed should only occur after setting all other states. This is to allow for a
@@ -3434,11 +3412,6 @@
         return 0;
     }
 
-    if (layer->isPendingRemoval()) {
-        ALOGW("Attempting to set client state on removed layer: %s", layer->getName().string());
-        return 0;
-    }
-
     uint32_t flags = 0;
 
     const uint32_t what = s.what;
@@ -3630,6 +3603,17 @@
     if (what & layer_state_t::eSidebandStreamChanged) {
         if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
     }
+
+    std::vector<sp<CallbackHandle>> callbackHandles;
+    if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
+        mTransactionCompletedThread.run();
+        for (const auto& [listener, callbackIds] : s.listenerCallbacks) {
+            callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
+        }
+    }
+    if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
+    // Do not put anything that updates layer state or modifies flags after
+    // setTransactionCompletedListener
     return flags;
 }
 
@@ -3642,11 +3626,6 @@
         return;
     }
 
-    if (layer->isPendingRemoval()) {
-        ALOGW("Attempting to destroy on removed layer: %s", layer->getName().string());
-        return;
-    }
-
     if (state.what & layer_state_t::eDestroySurface) {
         removeLayerLocked(mStateLock, layer);
     }
@@ -3763,7 +3742,7 @@
     }
 
     sp<BufferQueueLayer> layer =
-            new BufferQueueLayer(LayerCreationArgs(this, client, name, w, h, flags));
+            getFactory().createBufferQueueLayer(LayerCreationArgs(this, client, name, w, h, flags));
     status_t err = layer->setDefaultBufferProperties(w, h, format);
     if (err == NO_ERROR) {
         *handle = layer->getHandle();
@@ -3779,7 +3758,7 @@
                                                 uint32_t w, uint32_t h, uint32_t flags,
                                                 sp<IBinder>* handle, sp<Layer>* outLayer) {
     sp<BufferStateLayer> layer =
-            new BufferStateLayer(LayerCreationArgs(this, client, name, w, h, flags));
+            getFactory().createBufferStateLayer(LayerCreationArgs(this, client, name, w, h, flags));
     *handle = layer->getHandle();
     *outLayer = layer;
 
@@ -3790,7 +3769,7 @@
         const String8& name, uint32_t w, uint32_t h, uint32_t flags,
         sp<IBinder>* handle, sp<Layer>* outLayer)
 {
-    *outLayer = new ColorLayer(LayerCreationArgs(this, client, name, w, h, flags));
+    *outLayer = getFactory().createColorLayer(LayerCreationArgs(this, client, name, w, h, flags));
     *handle = (*outLayer)->getHandle();
     return NO_ERROR;
 }
@@ -3799,7 +3778,8 @@
         const String8& name, uint32_t w, uint32_t h, uint32_t flags,
         sp<IBinder>* handle, sp<Layer>* outLayer)
 {
-    *outLayer = new ContainerLayer(LayerCreationArgs(this, client, name, w, h, flags));
+    *outLayer =
+            getFactory().createContainerLayer(LayerCreationArgs(this, client, name, w, h, flags));
     *handle = (*outLayer)->getHandle();
     return NO_ERROR;
 }
@@ -3819,23 +3799,22 @@
     return err;
 }
 
-status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer)
+void SurfaceFlinger::markLayerPendingRemovalLocked(const Mutex&, const sp<Layer>& layer) {
+    mLayersPendingRemoval.add(layer);
+    mLayersRemoved = true;
+    setTransactionFlags(eTransactionNeeded);
+}
+
+void SurfaceFlinger::onHandleDestroyed(const sp<Layer>& layer)
 {
-    // called by ~LayerCleaner() when all references to the IBinder (handle)
-    // are gone
-    sp<Layer> l = layer.promote();
-    if (l == nullptr) {
-        // The layer has already been removed, carry on
-        return NO_ERROR;
-    }
-    // If we have a parent, then we can continue to live as long as it does.
-    return removeLayer(l, true);
+    Mutex::Autolock lock(mStateLock);
+    markLayerPendingRemovalLocked(mStateLock, layer);
 }
 
 // ---------------------------------------------------------------------------
 
 void SurfaceFlinger::onInitializeDisplays() {
-    const auto displayToken = mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY];
+    const auto displayToken = getInternalDisplayToken();
     if (!displayToken) return;
 
     // reset screen orientation and use primary layer stack
@@ -3859,7 +3838,7 @@
 
     setPowerModeInternal(display, HWC_POWER_MODE_NORMAL, /*stateLockHeld*/ false);
 
-    const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+    const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
     const nsecs_t period = activeConfig->getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
 
@@ -3876,16 +3855,18 @@
 
 void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode,
                                           bool stateLockHeld) {
-    const int32_t displayId = display->getId();
-    ALOGD("Setting power mode %d on display %d", mode, displayId);
-
-    int currentMode = display->getPowerMode();
-    if (mode == currentMode) {
+    if (display->isVirtual()) {
+        ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
         return;
     }
 
-    if (display->isVirtual()) {
-        ALOGW("Trying to set power mode for virtual display");
+    const auto displayId = display->getId();
+    LOG_ALWAYS_FATAL_IF(!displayId);
+
+    ALOGD("Setting power mode %d on display %" PRIu64, mode, *displayId);
+
+    int currentMode = display->getPowerMode();
+    if (mode == currentMode) {
         return;
     }
 
@@ -3901,12 +3882,10 @@
         mInterceptor->savePowerModeUpdate(mCurrentState.displays.valueAt(idx).sequenceId, mode);
     }
 
-    int32_t type = display->getDisplayType();
     if (currentMode == HWC_POWER_MODE_OFF) {
         // Turn on the display
-        getHwComposer().setPowerMode(type, mode);
+        getHwComposer().setPowerMode(*displayId, mode);
         if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
-            // FIXME: eventthread only knows about the main display right now
             if (mUseScheduler) {
                 mScheduler->onScreenAcquired(mAppConnectionHandle);
             } else {
@@ -3937,7 +3916,6 @@
             } else {
                 disableHardwareVsync(true); // also cancels any in-progress resync
             }
-            // FIXME: eventthread only knows about the main display right now
             if (mUseScheduler) {
                 mScheduler->onScreenReleased(mAppConnectionHandle);
             } else {
@@ -3945,15 +3923,14 @@
             }
         }
 
-        getHwComposer().setPowerMode(type, mode);
+        getHwComposer().setPowerMode(*displayId, mode);
         mVisibleRegionsDirty = true;
         // from this point on, SF will stop drawing on this display
     } else if (mode == HWC_POWER_MODE_DOZE ||
                mode == HWC_POWER_MODE_NORMAL) {
         // Update display while dozing
-        getHwComposer().setPowerMode(type, mode);
+        getHwComposer().setPowerMode(*displayId, mode);
         if (display->isPrimary() && currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
-            // FIXME: eventthread only knows about the main display right now
             if (mUseScheduler) {
                 mScheduler->onScreenAcquired(mAppConnectionHandle);
             } else {
@@ -3969,24 +3946,23 @@
             } else {
                 disableHardwareVsync(true); // also cancels any in-progress resync
             }
-            // FIXME: eventthread only knows about the main display right now
             if (mUseScheduler) {
                 mScheduler->onScreenReleased(mAppConnectionHandle);
             } else {
                 mEventThread->onScreenReleased();
             }
         }
-        getHwComposer().setPowerMode(type, mode);
+        getHwComposer().setPowerMode(*displayId, mode);
     } else {
         ALOGE("Attempting to set unknown power mode: %d\n", mode);
-        getHwComposer().setPowerMode(type, mode);
+        getHwComposer().setPowerMode(*displayId, mode);
     }
 
     if (display->isPrimary()) {
         mTimeStats.setPowerMode(mode);
     }
 
-    ALOGD("Finished setting power mode %d on display %d", mode, displayId);
+    ALOGD("Finished setting power mode %d on display %" PRIu64, mode, *displayId);
 }
 
 void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
@@ -4165,9 +4141,9 @@
         index++;
     }
 
-    if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
-        getHwComposer().isConnected(displayId)) {
-        const auto activeConfig = getBE().mHwc->getActiveConfig(displayId);
+    if (const auto displayId = getInternalDisplayId();
+        displayId && getHwComposer().isConnected(*displayId)) {
+        const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
         const nsecs_t period = activeConfig->getVsyncPeriod();
         result.appendFormat("%" PRId64 "\n", period);
     }
@@ -4308,13 +4284,17 @@
 
 void SurfaceFlinger::dumpDisplayIdentificationData(String8& result) const {
     for (const auto& [token, display] : mDisplays) {
-        const int32_t displayId = display->getId();
-        const auto hwcDisplayId = getHwComposer().getHwcDisplayId(displayId);
+        const auto displayId = display->getId();
+        if (!displayId) {
+            continue;
+        }
+        const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
         if (!hwcDisplayId) {
             continue;
         }
 
-        result.appendFormat("Display %d (HWC display %" PRIu64 "): ", displayId, *hwcDisplayId);
+        result.appendFormat("Display %" PRIu64 " (HWC display %" PRIu64 "): ", *displayId,
+                            *hwcDisplayId);
         uint8_t port;
         DisplayIdentificationData data;
         if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) {
@@ -4345,7 +4325,6 @@
         result.append(edid->displayName.data(), edid->displayName.length());
         result.append("\"\n");
     }
-    result.append("\n");
 }
 
 void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
@@ -4357,13 +4336,13 @@
     // TODO: print out if wide-color mode is active or not
 
     for (const auto& [token, display] : mDisplays) {
-        const int32_t displayId = display->getId();
-        if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+        const auto displayId = display->getId();
+        if (!displayId) {
             continue;
         }
 
-        result.appendFormat("Display %d color modes:\n", displayId);
-        std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
+        result.appendFormat("Display %" PRIu64 " color modes:\n", *displayId);
+        std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
         for (auto&& mode : modes) {
             result.appendFormat("    %s (%d)\n", decodeColorMode(mode).c_str(), mode);
         }
@@ -4379,17 +4358,13 @@
     std::string stringResult;
 
     for (const auto& [token, display] : mDisplays) {
-        const auto displayId = display->getId();
-        if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+        const auto it = getBE().mEndOfFrameCompositionInfo.find(token);
+        if (it == getBE().mEndOfFrameCompositionInfo.end()) {
             continue;
         }
 
-        const auto& compositionInfoIt = getBE().mEndOfFrameCompositionInfo.find(displayId);
-        if (compositionInfoIt == getBE().mEndOfFrameCompositionInfo.end()) {
-            break;
-        }
-        const auto& compositionInfoList = compositionInfoIt->second;
-        stringResult += base::StringPrintf("Display: %d\n", displayId);
+        const auto& compositionInfoList = it->second;
+        stringResult += base::StringPrintf("%s\n", display->getDebugName().c_str());
         stringResult += base::StringPrintf("numComponents: %zu\n", compositionInfoList.size());
         for (const auto& compositionInfo : compositionInfoList) {
             compositionInfo.dump(stringResult, nullptr);
@@ -4423,11 +4398,12 @@
     layersProto.set_color_transform(decodeColorTransform(display.getColorTransform()));
     layersProto.set_global_transform(static_cast<int32_t>(display.getOrientationTransform()));
 
-    const int32_t displayId = display.getId();
+    const auto displayId = display.getId();
+    LOG_ALWAYS_FATAL_IF(!displayId);
     mDrawingState.traverseInZOrder([&](Layer* layer) {
-        if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(displayId)) {
+        if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(*displayId)) {
             LayerProto* layerProto = layersProto.add_layers();
-            layer->writeToProto(layerProto, displayId);
+            layer->writeToProto(layerProto, *displayId);
         }
     });
 
@@ -4481,25 +4457,19 @@
 
     const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
     const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
-    if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
-        getHwComposer().isConnected(displayId)) {
-        const auto activeConfig = getHwComposer().getActiveConfig(displayId);
-        result.appendFormat("Display %d: "
-                "app phase %" PRId64 " ns, "
-                "sf phase %" PRId64 " ns, "
-                "early app phase %" PRId64 " ns, "
-                "early sf phase %" PRId64 " ns, "
-                "early app gl phase %" PRId64 " ns, "
-                "early sf gl phase %" PRId64 " ns, "
-                "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
-                displayId,
-                vsyncPhaseOffsetNs,
-                sfVsyncPhaseOffsetNs,
-                appEarlyOffset,
-                sfEarlyOffset,
-                appEarlyGlOffset,
-                sfEarlyGlOffset,
-                dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
+    if (const auto displayId = getInternalDisplayId();
+        displayId && getHwComposer().isConnected(*displayId)) {
+        const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
+        result.appendFormat("Display %" PRIu64 ": app phase %" PRId64 " ns, "
+                            "sf phase %" PRId64 " ns, "
+                            "early app phase %" PRId64 " ns, "
+                            "early sf phase %" PRId64 " ns, "
+                            "early app gl phase %" PRId64 " ns, "
+                            "early sf gl phase %" PRId64 " ns, "
+                            "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+                            *displayId, vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, appEarlyOffset,
+                            sfEarlyOffset, appEarlyGlOffset, sfEarlyGlOffset,
+                            dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
     }
     result.append("\n");
 
@@ -4552,12 +4522,9 @@
     result.append("SurfaceFlinger global state:\n");
     colorizer.reset(result);
 
-    HWComposer& hwc(getHwComposer());
-    const auto display = getDefaultDisplayDeviceLocked();
-
     getBE().mRenderEngine->dump(result);
 
-    if (display) {
+    if (const auto display = getDefaultDisplayDeviceLocked()) {
         display->undefinedRegion.dump(result, "undefinedRegion");
         result.appendFormat("  orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
                             display->isPoweredOn());
@@ -4566,8 +4533,9 @@
                         "  gpu_to_cpu_unsupported    : %d\n",
                         mTransactionFlags.load(), !mGpuToCpuSupported);
 
-    if (display) {
-        const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+    if (const auto displayId = getInternalDisplayId();
+        displayId && getHwComposer().isConnected(*displayId)) {
+        const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
         result.appendFormat("  refresh-rate              : %f fps\n"
                             "  x-dpi                     : %f\n"
                             "  y-dpi                     : %f\n",
@@ -4599,14 +4567,14 @@
      * HWC layer minidump
      */
     for (const auto& [token, display] : mDisplays) {
-        const int32_t displayId = display->getId();
-        if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+        const auto displayId = display->getId();
+        if (!displayId) {
             continue;
         }
 
-        result.appendFormat("Display %d HWC layers:\n", displayId);
+        result.appendFormat("Display %" PRIu64 " HWC layers:\n", *displayId);
         Layer::miniDumpHeader(result);
-        mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, displayId); });
+        mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, *displayId); });
         result.append("\n");
     }
 
@@ -4619,7 +4587,7 @@
     bool hwcDisabled = mDebugDisableHWC || mDebugRegion;
     result.appendFormat("  h/w composer %s\n",
             hwcDisabled ? "disabled" : "enabled");
-    hwc.dump(result);
+    getHwComposer().dump(result);
 
     /*
      * Dump gralloc state
@@ -4637,7 +4605,7 @@
     }
 }
 
-const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(int32_t displayId) {
+const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
     // Note: mStateLock is held here
     for (const auto& [token, display] : mDisplays) {
         if (display->getId() == displayId) {
@@ -4645,7 +4613,7 @@
         }
     }
 
-    ALOGE("%s: Invalid display %d", __FUNCTION__, displayId);
+    ALOGE("%s: Invalid display %" PRIu64, __FUNCTION__, displayId);
     static const Vector<sp<Layer>> empty;
     return empty;
 }
@@ -4746,6 +4714,7 @@
         case SET_TRANSACTION_STATE:
         // Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
         case CREATE_SCOPED_CONNECTION:
+        case GET_COLOR_MANAGEMENT:
         case GET_COMPOSITION_PREFERENCE: {
             return OK;
         }
@@ -4778,9 +4747,9 @@
         code == IBinder::SYSPROPS_TRANSACTION) {
         return OK;
     }
-    // Numbers from 1000 to 1029 are currently use for backdoors. The code
+    // Numbers from 1000 to 1031 are currently use for backdoors. The code
     // in onTransact verifies that the user is root, and has access to use SF.
-    if (code >= 1000 && code <= 1029) {
+    if (code >= 1000 && code <= 1031) {
         ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
         return OK;
     }
@@ -4976,11 +4945,9 @@
                 repaintEverything();
                 return NO_ERROR;
             }
-            // TODO(b/111505327): Find out whether the usage of 1024 can switch to 1030,
-            // deprecate 1024 if they can.
-            case 1024: { // Does device have wide color gamut display?
-                reply->writeBool(hasWideColorDisplay);
-                return NO_ERROR;
+            // Deprecate, use 1030 to check whether the device is color managed.
+            case 1024: {
+                return NAME_NOT_FOUND;
             }
             case 1025: { // Set layer tracing
                 n = data.readInt32();
@@ -5031,59 +4998,43 @@
                 reply->writeBool(getBE().mHwc->isUsingVrComposer());
                 return NO_ERROR;
             }
-            case 1029: {
-                // Code 1029 is an experimental feature that allows applications to
-                // simulate a high frequency panel by setting a multiplier and divisor
-                // on the VSYNC-sf clock.  If either the multiplier or divisor are
-                // 0, then the code simply return the current multiplier and divisor.
-                HWC2::Device::FrequencyScaler frequencyScaler;
-                frequencyScaler.multiplier = data.readInt32();
-                frequencyScaler.divisor = data.readInt32();
-
-                if ((frequencyScaler.multiplier == 0) || (frequencyScaler.divisor == 0)) {
-                    frequencyScaler = getBE().mHwc->getDisplayFrequencyScaleParameters();
-                    reply->writeInt32(frequencyScaler.multiplier);
-                    reply->writeInt32(frequencyScaler.divisor);
-                    return NO_ERROR;
-                }
-
-                if ((frequencyScaler.multiplier == 1) && (frequencyScaler.divisor == 1)) {
-                    if (mUseScheduler) {
-                        mScheduler->enableHardwareVsync();
-                    } else {
-                        enableHardwareVsync();
-                    }
-                } else {
-                    if (mUseScheduler) {
-                        mScheduler->disableHardwareVsync(true);
-                    } else {
-                        disableHardwareVsync(true);
-                    }
-                }
-                mPrimaryDispSync->scalePeriod(frequencyScaler);
-                getBE().mHwc->setDisplayFrequencyScaleParameters(frequencyScaler);
-
-                ATRACE_INT("PeriodMultiplier", frequencyScaler.multiplier);
-                ATRACE_INT("PeriodDivisor", frequencyScaler.divisor);
-
-                const hwc2_display_t hwcDisplayId = getBE().mHwc->getActiveConfig(
-                        DisplayDevice::DISPLAY_PRIMARY)->getDisplayId();
-
-                onHotplugReceived(getBE().mComposerSequenceId,
-                        hwcDisplayId, HWC2::Connection::Disconnected);
-                onHotplugReceived(getBE().mComposerSequenceId,
-                        hwcDisplayId, HWC2::Connection::Connected);
-                frequencyScaler = getBE().mHwc->getDisplayFrequencyScaleParameters();
-                reply->writeInt32(frequencyScaler.multiplier);
-                reply->writeInt32(frequencyScaler.divisor);
-
-                return NO_ERROR;
-            }
             // Is device color managed?
             case 1030: {
                 reply->writeBool(useColorManagement);
                 return NO_ERROR;
             }
+            // Override default composition data space
+            // adb shell service call SurfaceFlinger 1031 i32 1 DATASPACE_NUMBER DATASPACE_NUMBER \
+            // && adb shell stop zygote && adb shell start zygote
+            // to restore: adb shell service call SurfaceFlinger 1031 i32 0 && \
+            // adb shell stop zygote && adb shell start zygote
+            case 1031: {
+                Mutex::Autolock _l(mStateLock);
+                n = data.readInt32();
+                if (n) {
+                    n = data.readInt32();
+                    if (n) {
+                        Dataspace dataspace = static_cast<Dataspace>(n);
+                        if (!validateCompositionDataspace(dataspace)) {
+                            return BAD_VALUE;
+                        }
+                        mDefaultCompositionDataspace = dataspace;
+                    }
+                    n = data.readInt32();
+                    if (n) {
+                        Dataspace dataspace = static_cast<Dataspace>(n);
+                        if (!validateCompositionDataspace(dataspace)) {
+                            return BAD_VALUE;
+                        }
+                        mWideColorGamutCompositionDataspace = dataspace;
+                    }
+                } else {
+                    // restore composition data space.
+                    mDefaultCompositionDataspace = defaultCompositionDataspace;
+                    mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace;
+                }
+                return NO_ERROR;
+            }
         }
     }
     return err;
@@ -5108,7 +5059,8 @@
 };
 
 status_t SurfaceFlinger::captureScreen(const sp<IBinder>& displayToken,
-                                       sp<GraphicBuffer>* outBuffer, Rect sourceCrop,
+                                       sp<GraphicBuffer>* outBuffer, const Dataspace reqDataspace,
+                                       const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                        uint32_t reqWidth, uint32_t reqHeight,
                                        bool useIdentityTransform,
                                        ISurfaceComposer::Rotation rotation) {
@@ -5125,10 +5077,6 @@
         display = getDisplayDeviceLocked(displayToken);
         if (!display) return BAD_VALUE;
 
-        // ignore sourceCrop (i.e., use the projected logical display
-        // viewport) until the framework is fixed
-        sourceCrop.clear();
-
         // set the requested width/height to the logical display viewport size
         // by default
         if (reqWidth == 0 || reqHeight == 0) {
@@ -5137,23 +5085,27 @@
         }
     }
 
-    DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, renderAreaRotation);
+    DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace,
+                                 renderAreaRotation);
 
     auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
                                     display, std::placeholders::_1);
-    return captureScreenCommon(renderArea, traverseLayers, outBuffer, useIdentityTransform);
+    return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat,
+                               useIdentityTransform);
 }
 
 status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
-                                       sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+                                       sp<GraphicBuffer>* outBuffer, const Dataspace reqDataspace,
+                                       const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
                                        float frameScale, bool childrenOnly) {
     ATRACE_CALL();
 
     class LayerRenderArea : public RenderArea {
     public:
         LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
-                        int32_t reqWidth, int32_t reqHeight, bool childrenOnly)
-              : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR),
+                        int32_t reqWidth, int32_t reqHeight, Dataspace reqDataSpace,
+                        bool childrenOnly)
+              : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR, reqDataSpace),
                 mLayer(layer),
                 mCrop(crop),
                 mNeedsFiltering(false),
@@ -5200,7 +5152,7 @@
                 drawLayers();
             } else {
                 Rect bounds = getBounds();
-                screenshotParentLayer = new ContainerLayer(
+                screenshotParentLayer = mFlinger->getFactory().createContainerLayer(
                         LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
                                           bounds.getWidth(), bounds.getHeight(), 0));
 
@@ -5226,7 +5178,7 @@
     auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
     auto parent = layerHandle->owner.promote();
 
-    if (parent == nullptr || parent->isPendingRemoval()) {
+    if (parent == nullptr || parent->isRemovedFromCurrentState()) {
         ALOGE("captureLayers called with a removed parent");
         return NAME_NOT_FOUND;
     }
@@ -5260,7 +5212,7 @@
         reqHeight = 1;
     }
 
-    LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, childrenOnly);
+    LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, reqDataspace, childrenOnly);
 
     auto traverseLayers = [parent, childrenOnly](const LayerVector::Visitor& visitor) {
         parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
@@ -5272,19 +5224,23 @@
             visitor(layer);
         });
     };
-    return captureScreenCommon(renderArea, traverseLayers, outBuffer, false);
+    return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false);
 }
 
 status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
                                              TraverseLayersFunction traverseLayers,
                                              sp<GraphicBuffer>* outBuffer,
+                                             const ui::PixelFormat reqPixelFormat,
                                              bool useIdentityTransform) {
     ATRACE_CALL();
 
+    // TODO(b/116112787) Make buffer usage a parameter.
     const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
             GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
-    *outBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
-                                   HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot");
+    *outBuffer =
+            getFactory().createGraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
+                                             static_cast<android_pixel_format>(reqPixelFormat), 1,
+                                             usage, "screenshot");
 
     // This mutex protects syncFd and captureResult for communication of the return values from the
     // main thread back to this Binder thread
@@ -5360,8 +5316,7 @@
     const auto sourceCrop = renderArea.getSourceCrop();
     const auto rotation = renderArea.getRotationFlags();
 
-    // assume ColorMode::SRGB / RenderIntent::COLORIMETRIC
-    engine.setOutputDataSpace(Dataspace::SRGB);
+    engine.setOutputDataSpace(renderArea.getReqDataSpace());
     engine.setDisplayMaxLuminance(DisplayDevice::sDefaultMaxLumiance);
 
     // make sure to clear all GL error flags
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 658f04e..f5218b1 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -59,9 +59,10 @@
 #include "LayerBE.h"
 #include "LayerStats.h"
 #include "LayerVector.h"
-#include "StartPropertySetThread.h"
+#include "SurfaceFlingerFactory.h"
 #include "SurfaceInterceptor.h"
 #include "SurfaceTracing.h"
+#include "TransactionCompletedThread.h"
 
 #include "DisplayHardware/HWC2.h"
 #include "DisplayHardware/HWComposer.h"
@@ -76,10 +77,11 @@
 #include <map>
 #include <mutex>
 #include <queue>
+#include <set>
 #include <string>
 #include <thread>
+#include <unordered_map>
 #include <utility>
-#include "RenderArea.h"
 
 #include <layerproto/LayerProtoHeader.h>
 
@@ -222,8 +224,8 @@
     // instances. Each hardware composer instance gets a different sequence id.
     int32_t mComposerSequenceId;
 
-    std::unordered_map<int32_t, std::vector<CompositionInfo>> mCompositionInfo;
-    std::unordered_map<int32_t, std::vector<CompositionInfo>> mEndOfFrameCompositionInfo;
+    std::map<wp<IBinder>, std::vector<CompositionInfo>> mCompositionInfo;
+    std::map<wp<IBinder>, std::vector<CompositionInfo>> mEndOfFrameCompositionInfo;
 };
 
 
@@ -294,8 +296,14 @@
     // The data space and pixel format that SurfaceFlinger expects hardware composer
     // to composite efficiently. Meaning under most scenarios, hardware composer
     // will accept layers with the data space and pixel format.
-    static ui::Dataspace compositionDataSpace;
-    static ui::PixelFormat compositionPixelFormat;
+    static ui::Dataspace defaultCompositionDataspace;
+    static ui::PixelFormat defaultCompositionPixelFormat;
+
+    // The data space and pixel format that SurfaceFlinger expects hardware composer
+    // to composite efficiently for wide color gamut surfaces. Meaning under most scenarios,
+    // hardware composer will accept layers with the data space and pixel format.
+    static ui::Dataspace wideColorGamutCompositionDataspace;
+    static ui::PixelFormat wideColorGamutCompositionPixelFormat;
 
     static char const* getServiceName() ANDROID_API {
         return "SurfaceFlinger";
@@ -303,8 +311,8 @@
 
     struct SkipInitializationTag {};
     static constexpr SkipInitializationTag SkipInitialization;
-    explicit SurfaceFlinger(SkipInitializationTag) ANDROID_API;
-    SurfaceFlinger() ANDROID_API;
+    SurfaceFlinger(surfaceflinger::Factory&, SkipInitializationTag) ANDROID_API;
+    explicit SurfaceFlinger(surfaceflinger::Factory&) ANDROID_API;
 
     // must be called before clients can connect
     void init() ANDROID_API;
@@ -325,6 +333,8 @@
     // force full composition on all displays
     void repaintEverything();
 
+    surfaceflinger::Factory& getFactory() { return mFactory; }
+
     // returns the default Display
     sp<const DisplayDevice> getDefaultDisplayDevice() const {
         Mutex::Autolock _l(mStateLock);
@@ -340,7 +350,7 @@
 
     // enable/disable h/w composer event
     // TODO: this should be made accessible only to EventThread
-    void setVsyncEnabled(int disp, int enabled);
+    void setVsyncEnabled(EventThread::DisplayType displayType, bool enabled);
 
     // called on the main thread by MessageQueue when an internal message
     // is received
@@ -349,13 +359,20 @@
 
     // for debugging only
     // TODO: this should be made accessible only to HWComposer
-    const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int id);
+    const Vector<sp<Layer>>& getLayerSortedByZForHwcDisplay(DisplayId displayId);
 
     renderengine::RenderEngine& getRenderEngine() const { return *getBE().mRenderEngine; }
 
     bool authenticateSurfaceTextureLocked(
         const sp<IGraphicBufferProducer>& bufferProducer) const;
 
+    inline void onLayerCreated() { mNumLayers++; }
+    inline void onLayerDestroyed() { mNumLayers--; }
+
+    TransactionCompletedThread& getTransactionCompletedThread() {
+        return mTransactionCompletedThread;
+    }
+
 private:
     friend class Client;
     friend class DisplayEventConnection;
@@ -433,10 +450,14 @@
     virtual sp<IDisplayEventConnection> createDisplayEventConnection(
             ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp);
     virtual status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
-                                   Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-                                   bool useIdentityTransform, ISurfaceComposer::Rotation rotation);
+                                   const ui::Dataspace reqDataspace,
+                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                   uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                                   ISurfaceComposer::Rotation rotation);
     virtual status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
-                                   const Rect& sourceCrop, float frameScale, bool childrenOnly);
+                                   const ui::Dataspace reqDataspace,
+                                   const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
+                                   float frameScale, bool childrenOnly);
     virtual status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
     virtual status_t getDisplayConfigs(const sp<IBinder>& displayToken,
                                        Vector<DisplayInfo>* configs);
@@ -454,8 +475,10 @@
     virtual status_t enableVSyncInjections(bool enable);
     virtual status_t injectVSync(nsecs_t when);
     virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
-    status_t getCompositionPreference(ui::Dataspace* outDataSpace,
-                                      ui::PixelFormat* outPixelFormat) const override;
+    virtual status_t getColorManagement(bool* outGetColorManagement) const;
+    status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
+                                      ui::Dataspace* outWideColorGamutDataspace,
+                                      ui::PixelFormat* outWideColorGamutPixelFormat) const override;
 
     /* ------------------------------------------------------------------------
      * DeathRecipient interface
@@ -561,10 +584,12 @@
     // ISurfaceComposerClient::destroySurface()
     status_t onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle);
 
+    void markLayerPendingRemovalLocked(const Mutex& /* mStateLock */, const sp<Layer>& layer);
+
     // called when all clients have released all their references to
     // this layer meaning it is entirely safe to destroy all
     // resources associated to this layer.
-    status_t onLayerDestroyed(const wp<Layer>& layer);
+    void onHandleDestroyed(const sp<Layer>& layer);
 
     // remove a layer from SurfaceFlinger immediately
     status_t removeLayer(const sp<Layer>& layer, bool topLevelOnly = false);
@@ -586,7 +611,7 @@
     void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
                                 bool useIdentityTransform);
     status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
-                                 sp<GraphicBuffer>* outBuffer,
+                                 sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
                                  bool useIdentityTransform);
     status_t captureScreenImplLocked(const RenderArea& renderArea,
                                      TraverseLayersFunction traverseLayers,
@@ -595,7 +620,7 @@
     void traverseLayersInDisplay(const sp<const DisplayDevice>& display,
                                  const LayerVector::Visitor& visitor);
 
-    sp<StartPropertySetThread> mStartPropertySetThread = nullptr;
+    sp<StartPropertySetThread> mStartPropertySetThread;
 
     /* ------------------------------------------------------------------------
      * Properties
@@ -640,7 +665,10 @@
     }
 
     sp<DisplayDevice> getDefaultDisplayDeviceLocked() {
-        return getDisplayDeviceLocked(mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY]);
+        if (const auto token = getInternalDisplayToken()) {
+            return getDisplayDeviceLocked(token);
+        }
+        return nullptr;
     }
 
     // mark a region of a layer stack dirty. this updates the dirty
@@ -693,10 +721,10 @@
     void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
     void doTracing(const char* where);
     void logLayerStats();
-    void doDisplayComposition(const sp<const DisplayDevice>& display, const Region& dirtyRegion);
+    void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion);
 
     // This fails if using GL and the surface has been destroyed.
-    bool doComposeSurfaces(const sp<const DisplayDevice>& display);
+    bool doComposeSurfaces(const sp<DisplayDevice>& display);
 
     void postFramebuffer(const sp<DisplayDevice>& display);
     void postFrame();
@@ -705,10 +733,8 @@
     /* ------------------------------------------------------------------------
      * Display management
      */
-    DisplayDevice::DisplayType determineDisplayType(hwc2_display_t hwcDisplayId,
-                                                    HWC2::Connection connection) const;
     sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
-                                                    int32_t displayId,
+                                                    const std::optional<DisplayId>& displayId,
                                                     const DisplayDeviceState& state,
                                                     const sp<DisplaySurface>& dispSurface,
                                                     const sp<IGraphicBufferProducer>& producer);
@@ -740,6 +766,37 @@
     }
 
 private:
+    sp<IBinder> getPhysicalDisplayToken(DisplayId displayId) const {
+        const auto it = mPhysicalDisplayTokens.find(displayId);
+        return it != mPhysicalDisplayTokens.end() ? it->second : nullptr;
+    }
+
+    std::optional<DisplayId> getPhysicalDisplayId(const sp<IBinder>& displayToken) const {
+        for (const auto& [id, token] : mPhysicalDisplayTokens) {
+            if (token == displayToken) {
+                return id;
+            }
+        }
+        return {};
+    }
+
+    // TODO(b/74619554): Remove special cases for primary display.
+    sp<IBinder> getInternalDisplayToken() const {
+        const auto displayId = getInternalDisplayId();
+        return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+    }
+
+    std::optional<DisplayId> getInternalDisplayId() const {
+        const auto hwcDisplayId = getHwComposer().getInternalHwcDisplayId();
+        return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
+    }
+
+    // TODO(b/74619554): Remove special cases for external display.
+    std::optional<DisplayId> getExternalDisplayId() const {
+        const auto hwcDisplayId = getHwComposer().getExternalHwcDisplayId();
+        return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
+    }
+
     void listLayersLocked(const Vector<String16>& args, size_t& index, String8& result) const;
     void dumpStatsLocked(const Vector<String16>& args, size_t& index, String8& result) const;
     void clearStatsLocked(const Vector<String16>& args, size_t& index, String8& result);
@@ -781,6 +838,8 @@
      * Attributes
      */
 
+    surfaceflinger::Factory& mFactory;
+
     // access must be protected by mStateLock
     mutable Mutex mStateLock;
     State mCurrentState{LayerVector::StateSet::Current};
@@ -815,7 +874,7 @@
     std::unique_ptr<VSyncSource> mSfEventThreadSource;
     std::unique_ptr<InjectVSyncSource> mVSyncInjector;
     std::unique_ptr<EventControlThread> mEventControlThread;
-    sp<IBinder> mDisplayTokens[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
+    std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
 
     VSyncModulator mVsyncModulator;
 
@@ -858,19 +917,20 @@
     nsecs_t mPostFramebufferTime;
     bool mForceFullDamage;
     bool mPropagateBackpressure = true;
-    std::unique_ptr<SurfaceInterceptor> mInterceptor =
-            std::make_unique<impl::SurfaceInterceptor>(this);
+    std::unique_ptr<SurfaceInterceptor> mInterceptor{mFactory.createSurfaceInterceptor(this)};
     SurfaceTracing mTracing;
     LayerStats mLayerStats;
     TimeStats& mTimeStats = TimeStats::getInstance();
     bool mUseHwcVirtualDisplays = false;
     std::atomic<uint32_t> mFrameMissedCount{0};
 
+    TransactionCompletedThread mTransactionCompletedThread;
+
     // Restrict layers to use two buffers in their bufferqueues.
     bool mLayerTripleBufferingDisabled = false;
 
     // these are thread safe
-    mutable std::unique_ptr<MessageQueue> mEventQueue{std::make_unique<impl::MessageQueue>()};
+    mutable std::unique_ptr<MessageQueue> mEventQueue{mFactory.createMessageQueue()};
     FrameTracker mAnimFrameTracker;
     std::unique_ptr<DispSync> mPrimaryDispSync;
 
@@ -917,16 +977,8 @@
     // Applied on Display P3 layers when the render intent is non-colorimetric.
     mat4 mEnhancedSaturationMatrix;
 
-    using CreateBufferQueueFunction =
-            std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
-                               sp<IGraphicBufferConsumer>* /* outConsumer */,
-                               bool /* consumerIsSurfaceFlinger */)>;
-    CreateBufferQueueFunction mCreateBufferQueue;
-
-    using CreateNativeWindowSurfaceFunction =
-            std::function<std::unique_ptr<surfaceflinger::NativeWindowSurface>(
-                    const sp<IGraphicBufferProducer>&)>;
-    CreateNativeWindowSurfaceFunction mCreateNativeWindowSurface;
+    ui::Dataspace mDefaultCompositionDataspace;
+    ui::Dataspace mWideColorGamutCompositionDataspace;
 
     SurfaceFlingerBE mBE;
 
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index b37d6f0..1261aee 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -14,13 +14,112 @@
  * limitations under the License.
  */
 
-#include "SurfaceFlingerFactory.h"
+#include <ui/GraphicBuffer.h>
+
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "ColorLayer.h"
+#include "ContainerLayer.h"
+#include "DisplayDevice.h"
+#include "Layer.h"
+#include "NativeWindowSurface.h"
+#include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
+#include "SurfaceFlingerFactory.h"
+#include "SurfaceInterceptor.h"
+
+#include "DisplayHardware/ComposerHal.h"
+#include "Scheduler/DispSync.h"
+#include "Scheduler/EventControlThread.h"
+#include "Scheduler/MessageQueue.h"
+#include "Scheduler/Scheduler.h"
 
 namespace android::surfaceflinger {
 
 sp<SurfaceFlinger> createSurfaceFlinger() {
-    return new SurfaceFlinger();
+    class Factory final : public surfaceflinger::Factory {
+    public:
+        Factory() = default;
+        ~Factory() = default;
+
+        std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework,
+                                                 int64_t dispSyncPresentTimeOffset) override {
+            // Note: We create a local temporary with the real DispSync implementation
+            // type temporarily so we can initialize it with the configured values,
+            // before storing it for more generic use using the interface type.
+            auto primaryDispSync = std::make_unique<android::impl::DispSync>(name);
+            primaryDispSync->init(hasSyncFramework, dispSyncPresentTimeOffset);
+            return primaryDispSync;
+        }
+
+        std::unique_ptr<EventControlThread> createEventControlThread(
+                std::function<void(bool)> setVSyncEnabled) override {
+            return std::make_unique<android::impl::EventControlThread>(setVSyncEnabled);
+        }
+
+        std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override {
+            return std::make_unique<HWComposer>(
+                    std::make_unique<Hwc2::impl::Composer>(serviceName));
+        }
+
+        std::unique_ptr<MessageQueue> createMessageQueue() override {
+            return std::make_unique<android::impl::MessageQueue>();
+        }
+
+        std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) override {
+            return std::make_unique<Scheduler>(callback);
+        }
+
+        std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(
+                SurfaceFlinger* flinger) override {
+            return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
+        }
+
+        sp<StartPropertySetThread> createStartPropertySetThread(
+                bool timestampPropertyValue) override {
+            return new StartPropertySetThread(timestampPropertyValue);
+        }
+
+        sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) override {
+            return new DisplayDevice(std::move(creationArgs));
+        }
+
+        sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
+                                              uint32_t layerCount, uint64_t usage,
+                                              std::string requestorName) override {
+            return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+        }
+
+        void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+                               sp<IGraphicBufferConsumer>* outConsumer,
+                               bool consumerIsSurfaceFlinger) override {
+            BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
+        }
+
+        std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
+                const sp<IGraphicBufferProducer>& producer) override {
+            return surfaceflinger::impl::createNativeWindowSurface(producer);
+        }
+
+        sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override {
+            return new ContainerLayer(args);
+        }
+
+        sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override {
+            return new BufferQueueLayer(args);
+        }
+
+        sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override {
+            return new BufferStateLayer(args);
+        }
+
+        sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) override {
+            return new ColorLayer(args);
+        }
+    };
+    static Factory factory;
+
+    return new SurfaceFlinger(factory);
 }
 
 } // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 65eb797..496bbf0 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -16,15 +16,76 @@
 
 #pragma once
 
+#include <cinttypes>
+#include <functional>
+#include <memory>
+#include <string>
+
 #include <cutils/compiler.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
 
+typedef int32_t PixelFormat;
+
+class BufferQueueLayer;
+class BufferStateLayer;
+class ColorLayer;
+class ContainerLayer;
+class DisplayDevice;
+class DispSync;
+class EventControlThread;
+class GraphicBuffer;
+class HWComposer;
+class IGraphicBufferConsumer;
+class IGraphicBufferProducer;
+class MessageQueue;
+class Scheduler;
+class StartPropertySetThread;
 class SurfaceFlinger;
+class SurfaceInterceptor;
+
+struct DisplayDeviceCreationArgs;
+struct LayerCreationArgs;
 
 namespace surfaceflinger {
 
+class NativeWindowSurface;
+
+// The interface that SurfaceFlinger uses to create all of the implementations
+// of each interface.
+class Factory {
+public:
+    virtual std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework,
+                                                     int64_t dispSyncPresentTimeOffset) = 0;
+    virtual std::unique_ptr<EventControlThread> createEventControlThread(
+            std::function<void(bool)> setVSyncEnabled) = 0;
+    virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
+    virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
+    virtual std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) = 0;
+    virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
+
+    virtual sp<StartPropertySetThread> createStartPropertySetThread(
+            bool timestampPropertyValue) = 0;
+    virtual sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&&) = 0;
+    virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height,
+                                                  PixelFormat format, uint32_t layerCount,
+                                                  uint64_t usage, std::string requestorName) = 0;
+    virtual void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+                                   sp<IGraphicBufferConsumer>* outConsumer,
+                                   bool consumerIsSurfaceFlinger) = 0;
+    virtual std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
+            const sp<IGraphicBufferProducer>&) = 0;
+
+    virtual sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) = 0;
+    virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
+    virtual sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) = 0;
+    virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
+
+protected:
+    ~Factory() = default;
+};
+
 ANDROID_API sp<SurfaceFlinger> createSurfaceFlinger();
 
 } // namespace surfaceflinger
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 57bda5a..7faaff6 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -495,8 +495,10 @@
     DisplayCreation* creation(increment->mutable_display_creation());
     creation->set_id(info.sequenceId);
     creation->set_name(info.displayName);
-    creation->set_type(info.type);
     creation->set_is_secure(info.isSecure);
+    if (info.displayId) {
+        creation->set_display_id(*info.displayId);
+    }
 }
 
 void SurfaceInterceptor::addDisplayDeletionLocked(Increment* increment, int32_t sequenceId) {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 43fa262..9730e8c 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -173,8 +173,8 @@
         ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
               timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
 
+        const std::string& layerName = layerRecord.layerName;
         if (prevTimeRecord.ready) {
-            const std::string& layerName = layerRecord.layerName;
             if (!mTimeStats.stats.count(layerName)) {
                 mTimeStats.stats[layerName].layerName = layerName;
                 mTimeStats.stats[layerName].packageName = getPackageName(layerName);
@@ -220,6 +220,18 @@
                   timeRecords[0].frameTime.frameNumber, presentToPresentMs);
             timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
         }
+
+        // Output additional trace points to track frame time.
+        ATRACE_INT64(("TimeStats-Post - " + layerName).c_str(), timeRecords[0].frameTime.postTime);
+        ATRACE_INT64(("TimeStats-Acquire - " + layerName).c_str(),
+                     timeRecords[0].frameTime.acquireTime);
+        ATRACE_INT64(("TimeStats-Latch - " + layerName).c_str(),
+                     timeRecords[0].frameTime.latchTime);
+        ATRACE_INT64(("TimeStats-Desired - " + layerName).c_str(),
+                     timeRecords[0].frameTime.desiredTime);
+        ATRACE_INT64(("TimeStats-Present - " + layerName).c_str(),
+                     timeRecords[0].frameTime.presentTime);
+
         prevTimeRecord = timeRecords[0];
         timeRecords.pop_front();
         layerRecord.waitData--;
@@ -241,25 +253,18 @@
     return std::regex_match(layerName.begin(), layerName.end(), layerNameRegex);
 }
 
-void TimeStats::setLayerName(int32_t layerID, const std::string& layerName) {
+void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
+                            nsecs_t postTime) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
-    ALOGV("[%d]-[%s]", layerID, layerName.c_str());
+    ALOGV("[%d]-[%" PRIu64 "]-[%s]-PostTime[%" PRId64 "]", layerID, frameNumber, layerName.c_str(),
+          postTime);
 
     std::lock_guard<std::mutex> lock(mMutex);
     if (!mTimeStatsTracker.count(layerID) && layerNameIsValid(layerName)) {
         mTimeStatsTracker[layerID].layerName = layerName;
     }
-}
-
-void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime) {
-    if (!mEnabled.load()) return;
-
-    ATRACE_CALL();
-    ALOGV("[%d]-[%" PRIu64 "]-PostTime[%" PRId64 "]", layerID, frameNumber, postTime);
-
-    std::lock_guard<std::mutex> lock(mMutex);
     if (!mTimeStatsTracker.count(layerID)) return;
     LayerRecord& layerRecord = mTimeStatsTracker[layerID];
     if (layerRecord.timeRecords.size() == MAX_NUM_TIME_RECORDS) {
@@ -451,6 +456,8 @@
 }
 
 void TimeStats::flushPowerTimeLocked() {
+    if (!mEnabled.load()) return;
+
     nsecs_t curTime = systemTime();
     // elapsedTime is in milliseconds.
     int64_t elapsedTime = (curTime - mPowerTime.prevTime) / 1000000;
@@ -500,10 +507,14 @@
         ALOGV("GlobalPresentFenceTime[%" PRId64 "]",
               mGlobalRecord.presentFences.front()->getSignalTime());
 
-        const int32_t presentToPresentMs = msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
-        ALOGV("Global present2present[%d]", presentToPresentMs);
+        if (mGlobalRecord.prevPresentTime != 0) {
+            const int32_t presentToPresentMs =
+                    msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
+            ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]",
+                  presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime);
+            mTimeStats.presentToPresent.insert(presentToPresentMs);
+        }
 
-        mTimeStats.presentToPresent.insert(presentToPresentMs);
         mGlobalRecord.prevPresentTime = curPresentTime;
         mGlobalRecord.presentFences.pop_front();
     }
@@ -514,7 +525,15 @@
 
     ATRACE_CALL();
     std::lock_guard<std::mutex> lock(mMutex);
-    if (presentFence == nullptr) {
+    if (presentFence == nullptr || !presentFence->isValid()) {
+        mGlobalRecord.prevPresentTime = 0;
+        return;
+    }
+
+    if (mPowerTime.powerMode != HWC_POWER_MODE_NORMAL) {
+        // Try flushing the last present fence on HWC_POWER_MODE_NORMAL.
+        flushAvailableGlobalRecordsToStatsLocked();
+        mGlobalRecord.presentFences.clear();
         mGlobalRecord.prevPresentTime = 0;
         return;
     }
@@ -537,10 +556,10 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    ALOGD("Enabled");
     mEnabled.store(true);
     mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
     mPowerTime.prevTime = systemTime();
+    ALOGD("Enabled");
 }
 
 void TimeStats::disable() {
@@ -549,16 +568,17 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    ALOGD("Disabled");
+    flushPowerTimeLocked();
     mEnabled.store(false);
     mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+    ALOGD("Disabled");
 }
 
 void TimeStats::clear() {
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    ALOGD("Cleared");
+    mTimeStatsTracker.clear();
     mTimeStats.stats.clear();
     mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
     mTimeStats.statsEnd = 0;
@@ -568,6 +588,9 @@
     mTimeStats.displayOnTime = 0;
     mTimeStats.presentToPresent.hist.clear();
     mPowerTime.prevTime = systemTime();
+    mGlobalRecord.prevPresentTime = 0;
+    mGlobalRecord.presentFences.clear();
+    ALOGD("Cleared");
 }
 
 bool TimeStats::isEnabled() {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index d1e554c..184bf40 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -86,8 +86,8 @@
     void incrementMissedFrames();
     void incrementClientCompositionFrames();
 
-    void setLayerName(int32_t layerID, const std::string& layerName);
-    void setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime);
+    void setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
+                     nsecs_t postTime);
     void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime);
     void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime);
     void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime);
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index c701224..599ff5c 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -39,7 +39,7 @@
     if (delta < 0) return;
     // std::lower_bound won't work on out of range values
     if (delta > histogramConfig[HISTOGRAM_SIZE - 1]) {
-        hist[histogramConfig[HISTOGRAM_SIZE - 1]]++;
+        hist[histogramConfig[HISTOGRAM_SIZE - 1]] += delta / histogramConfig[HISTOGRAM_SIZE - 1];
         return;
     }
     auto iter = std::lower_bound(histogramConfig.begin(), histogramConfig.end(), delta);
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
new file mode 100644
index 0000000..9b9dc57
--- /dev/null
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "TransactionCompletedThread"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "TransactionCompletedThread.h"
+
+#include <cinttypes>
+
+#include <binder/IInterface.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+TransactionCompletedThread::~TransactionCompletedThread() {
+    {
+        std::lock_guard lock(mMutex);
+        mKeepRunning = false;
+        mConditionVariable.notify_all();
+    }
+
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+
+    {
+        std::lock_guard lock(mMutex);
+        for (const auto& [listener, listenerStats] : mListenerStats) {
+            listener->unlinkToDeath(mDeathRecipient);
+        }
+    }
+}
+
+void TransactionCompletedThread::run() {
+    std::lock_guard lock(mMutex);
+    if (mRunning) {
+        return;
+    }
+    mDeathRecipient = new ThreadDeathRecipient();
+    mRunning = true;
+    mThread = std::thread(&TransactionCompletedThread::threadMain, this);
+}
+
+void TransactionCompletedThread::registerPendingLatchedCallbackHandle(
+        const sp<CallbackHandle>& handle) {
+    std::lock_guard lock(mMutex);
+
+    sp<IBinder> listener = IInterface::asBinder(handle->listener);
+    const auto& callbackIds = handle->callbackIds;
+
+    mPendingTransactions[listener][callbackIds]++;
+}
+
+void TransactionCompletedThread::addLatchedCallbackHandles(
+        const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
+        const sp<Fence>& previousReleaseFence) {
+    std::lock_guard lock(mMutex);
+
+    // If the previous release fences have not signaled, something as probably gone wrong.
+    // Store the fences and check them again before sending a callback.
+    if (previousReleaseFence &&
+        previousReleaseFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
+        ALOGD("release fence from the previous frame has not signaled");
+        mPreviousReleaseFences.push_back(previousReleaseFence);
+    }
+
+    for (const auto& handle : handles) {
+        auto listener = mPendingTransactions.find(IInterface::asBinder(handle->listener));
+        auto& pendingCallbacks = listener->second;
+        auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
+
+        if (pendingCallback != pendingCallbacks.end()) {
+            auto& pendingCount = pendingCallback->second;
+
+            // Decrease the pending count for this listener
+            if (--pendingCount == 0) {
+                pendingCallbacks.erase(pendingCallback);
+            }
+        } else {
+            ALOGE("there are more latched callbacks than there were registered callbacks");
+        }
+
+        addCallbackHandle(handle, latchTime);
+    }
+}
+
+void TransactionCompletedThread::addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle) {
+    std::lock_guard lock(mMutex);
+    addCallbackHandle(handle);
+}
+
+void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
+                                                   nsecs_t latchTime) {
+    const sp<IBinder> listener = IInterface::asBinder(handle->listener);
+
+    // If we don't already have a reference to this listener, linkToDeath so we get a notification
+    // if it dies.
+    if (mListenerStats.count(listener) == 0) {
+        status_t error = listener->linkToDeath(mDeathRecipient);
+        if (error != NO_ERROR) {
+            ALOGE("cannot add callback handle because linkToDeath failed, err: %d", error);
+            return;
+        }
+    }
+
+    auto& listenerStats = mListenerStats[listener];
+    listenerStats.listener = handle->listener;
+
+    auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
+    transactionStats.latchTime = latchTime;
+    transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
+                                               handle->releasePreviousBuffer);
+}
+
+void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mPresentFence = presentFence;
+}
+
+void TransactionCompletedThread::sendCallbacks() {
+    std::lock_guard lock(mMutex);
+    if (mRunning) {
+        mConditionVariable.notify_all();
+    }
+}
+
+void TransactionCompletedThread::threadMain() {
+    std::lock_guard lock(mMutex);
+
+    while (mKeepRunning) {
+        mConditionVariable.wait(mMutex);
+
+        // Present fence should fire almost immediately. If the fence has not signaled in 100ms,
+        // there is a major problem and it will probably never fire.
+        nsecs_t presentTime = -1;
+        if (mPresentFence) {
+            status_t status = mPresentFence->wait(100);
+            if (status == NO_ERROR) {
+                presentTime = mPresentFence->getSignalTime();
+            } else {
+                ALOGE("present fence has not signaled, err %d", status);
+            }
+        }
+
+        // We should never hit this case. The release fences from the previous frame should have
+        // signaled long before the current frame is presented.
+        for (const auto& fence : mPreviousReleaseFences) {
+            status_t status = fence->wait(100);
+            if (status != NO_ERROR) {
+                ALOGE("previous release fence has not signaled, err %d", status);
+            }
+        }
+
+        // For each listener
+        auto it = mListenerStats.begin();
+        while (it != mListenerStats.end()) {
+            auto& [listener, listenerStats] = *it;
+
+            // For each transaction
+            bool sendCallback = true;
+            for (auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
+                // If we are still waiting on the callback handles for this transaction, skip it
+                if (mPendingTransactions[listener].count(callbackIds) != 0) {
+                    sendCallback = false;
+                    break;
+                }
+
+                // If the transaction has been latched
+                if (transactionStats.latchTime >= 0) {
+                    // If the present time is < 0, this transaction has been latched but not
+                    // presented. Skip it for now. This can happen when a new transaction comes
+                    // in between the latch and present steps. sendCallbacks is called by
+                    // SurfaceFlinger when the transaction is received to ensure that if the
+                    // transaction that didn't update state it still got a callback.
+                    if (presentTime < 0) {
+                        sendCallback = false;
+                        break;
+                    }
+
+                    transactionStats.presentTime = presentTime;
+                }
+            }
+            // If the listener has no pending transactions and all latched transactions have been
+            // presented
+            if (sendCallback) {
+                // If the listener is still alive
+                if (listener->isBinderAlive()) {
+                    // Send callback
+                    listenerStats.listener->onTransactionCompleted(listenerStats);
+                    listener->unlinkToDeath(mDeathRecipient);
+                }
+                it = mListenerStats.erase(it);
+            } else {
+                it++;
+            }
+        }
+
+        if (mPresentFence) {
+            mPresentFence.clear();
+            mPreviousReleaseFences.clear();
+        }
+    }
+}
+
+// -----------------------------------------------------------------------
+
+CallbackHandle::CallbackHandle(const sp<ITransactionCompletedListener>& transactionListener,
+                               const std::vector<CallbackId>& ids, const sp<IBinder>& sc)
+      : listener(transactionListener), callbackIds(ids), surfaceControl(sc) {}
+
+} // namespace android
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
new file mode 100644
index 0000000..5af4097
--- /dev/null
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+
+#include <android-base/thread_annotations.h>
+
+#include <binder/IBinder.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <ui/Fence.h>
+
+namespace android {
+
+class CallbackHandle : public RefBase {
+public:
+    CallbackHandle(const sp<ITransactionCompletedListener>& transactionListener,
+                   const std::vector<CallbackId>& ids, const sp<IBinder>& sc);
+
+    sp<ITransactionCompletedListener> listener;
+    std::vector<CallbackId> callbackIds;
+    sp<IBinder> surfaceControl;
+
+    bool releasePreviousBuffer = false;
+    nsecs_t acquireTime = -1;
+};
+
+class TransactionCompletedThread {
+public:
+    ~TransactionCompletedThread();
+
+    void run();
+
+    // Informs the TransactionCompletedThread that there is a Transaction with a CallbackHandle
+    // that needs to be latched and presented this frame. This function should be called once the
+    // layer has received the CallbackHandle so the TransactionCompletedThread knows not to send
+    // a callback for that Listener/Transaction pair until that CallbackHandle has been latched and
+    // presented.
+    void registerPendingLatchedCallbackHandle(const sp<CallbackHandle>& handle);
+    // Notifies the TransactionCompletedThread that a pending CallbackHandle has been latched.
+    void addLatchedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
+                                   const sp<Fence>& previousReleaseFence);
+
+    // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
+    // presented this frame.
+    void addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle);
+
+    void addPresentFence(const sp<Fence>& presentFence);
+
+    void sendCallbacks();
+
+private:
+    void threadMain();
+
+    void addCallbackHandle(const sp<CallbackHandle>& handle, nsecs_t latchTime = -1)
+            REQUIRES(mMutex);
+
+    class ThreadDeathRecipient : public IBinder::DeathRecipient {
+    public:
+        // This function is a no-op. isBinderAlive needs a linked DeathRecipient to work.
+        // Death recipients needs a binderDied function.
+        //
+        // (isBinderAlive checks if BpBinder's mAlive is 0. mAlive is only set to 0 in sendObituary.
+        // sendObituary is only called if linkToDeath was called with a DeathRecipient.)
+        void binderDied(const wp<IBinder>& /*who*/) override {}
+    };
+    sp<ThreadDeathRecipient> mDeathRecipient;
+
+    struct IBinderHash {
+        std::size_t operator()(const sp<IBinder>& strongPointer) const {
+            return std::hash<IBinder*>{}(strongPointer.get());
+        }
+    };
+
+    std::thread mThread;
+
+    std::mutex mMutex;
+    std::condition_variable_any mConditionVariable;
+
+    std::unordered_map<
+            sp<IBinder /*listener*/>,
+            std::unordered_map<std::vector<CallbackId>, uint32_t /*count*/, CallbackIdsHash>,
+            IBinderHash>
+            mPendingTransactions GUARDED_BY(mMutex);
+    std::unordered_map<sp<IBinder /*listener*/>, ListenerStats, IBinderHash> mListenerStats
+            GUARDED_BY(mMutex);
+
+    bool mRunning GUARDED_BY(mMutex) = false;
+    bool mKeepRunning GUARDED_BY(mMutex) = true;
+
+    sp<Fence> mPresentFence GUARDED_BY(mMutex);
+    std::vector<sp<Fence>> mPreviousReleaseFences GUARDED_BY(mMutex);
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 9c2edca..92ae87b 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -28,7 +28,6 @@
 #include <cutils/sched_policy.h>
 #include <displayservice/DisplayService.h>
 #include <hidl/LegacySupport.h>
-#include "GpuService.h"
 #include "SurfaceFlinger.h"
 #include "SurfaceFlingerFactory.h"
 
@@ -104,10 +103,6 @@
     sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                    IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
 
-    // publish GpuService
-    sp<GpuService> gpuservice = new GpuService();
-    sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
-
     startDisplayService(); // dependency on SF getting registered above
 
     struct sched_param param = {0};
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 9e762f0..a73ec6c 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -267,8 +267,9 @@
     sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
     std::function<status_t()> condition = [=]() {
         sp<GraphicBuffer> outBuffer;
-        return ScreenshotClient::capture(display, Rect(), 0 /*reqWidth*/, 0 /*reqHeight*/, false,
-                                         ROTATION, &outBuffer);
+        return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB,
+                                         ui::PixelFormat::RGBA_8888, Rect(), 0 /*reqWidth*/,
+                                         0 /*reqHeight*/, false, ROTATION, &outBuffer);
     };
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
 }
@@ -278,8 +279,9 @@
     sp<GraphicBuffer> outBuffer;
     std::function<status_t()> condition = [=]() {
         sp<GraphicBuffer> outBuffer;
-        return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(), Rect(), FRAME_SCALE,
-                                               &outBuffer);
+        return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(),
+                                               ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
+                                               Rect(), FRAME_SCALE, &outBuffer);
     };
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
 }
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index aed1f78..988454a 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -15,9 +15,12 @@
  */
 
 #include <algorithm>
+#include <chrono>
+#include <cinttypes>
 #include <functional>
 #include <limits>
 #include <ostream>
+#include <thread>
 
 #include <gtest/gtest.h>
 
@@ -30,6 +33,7 @@
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
 
+#include <ui/ColorSpace.h>
 #include <ui/DisplayInfo.h>
 #include <ui/Rect.h>
 #include <utils/String8.h>
@@ -63,6 +67,7 @@
 const Color Color::TRANSPARENT{0, 0, 0, 0};
 
 using android::hardware::graphics::common::V1_1::BufferUsage;
+using namespace std::chrono_literals;
 
 std::ostream& operator<<(std::ostream& os, const Color& color) {
     os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
@@ -314,6 +319,10 @@
         ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
 
         ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
+
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        sp<IBinder> binder = sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+        ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
     }
 
     virtual void TearDown() {
@@ -322,10 +331,11 @@
         mClient = 0;
     }
 
-    virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+    virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client,
+                                           const char* name, uint32_t width, uint32_t height,
                                            uint32_t flags = 0) {
         auto layer =
-                mClient->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags);
+                client->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags);
         EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
 
         Transaction t;
@@ -344,6 +354,11 @@
         return layer;
     }
 
+    virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+                                           uint32_t flags = 0) {
+        return createLayer(mClient, name, width, height, flags);
+    }
+
     ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
         // wait for previous transactions (such as setSize) to complete
         Transaction().apply(true);
@@ -474,6 +489,8 @@
     void setMatrixWithResizeHelper(uint32_t layerType);
 
     sp<SurfaceControl> mBlackBgSurface;
+    bool mColorManagementUsed;
+
 private:
     void SetUpDisplay() {
         mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
@@ -1951,7 +1968,7 @@
                               "test");
     fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
 
-    sp<Fence> fence = new Fence(-1);
+    sp<Fence> fence = Fence::NO_FENCE;
 
     Transaction()
             .setBuffer(layer, buffer)
@@ -2069,6 +2086,47 @@
     Transaction().setSidebandStream(layer, nullptr).apply();
 }
 
+class ColorTransformHelper {
+public:
+    static void DegammaColorSingle(half& s) {
+        if (s <= 0.03928f)
+            s = s / 12.92f;
+        else
+            s = pow((s + 0.055f) / 1.055f, 2.4f);
+    }
+
+    static void DegammaColor(half3& color) {
+        DegammaColorSingle(color.r);
+        DegammaColorSingle(color.g);
+        DegammaColorSingle(color.b);
+    }
+
+    static void GammaColorSingle(half& s) {
+        if (s <= 0.0031308f) {
+            s = s * 12.92f;
+        } else {
+            s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f;
+        }
+    }
+
+    static void GammaColor(half3& color) {
+        GammaColorSingle(color.r);
+        GammaColorSingle(color.g);
+        GammaColorSingle(color.b);
+    }
+
+    static void applyMatrix(half3& color, const mat3& mat) {
+        half3 ret = half3(0);
+
+        for (int i = 0; i < 3; i++) {
+            for (int j = 0; j < 3; j++) {
+                ret[i] = ret[i] + color[j] * mat[j][i];
+            }
+        }
+        color = ret;
+    }
+};
+
 TEST_F(LayerTransactionTest, SetColorTransformBasic) {
     sp<SurfaceControl> colorLayer;
     ASSERT_NO_FATAL_FAILURE(
@@ -2081,22 +2139,659 @@
     }
 
     const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
-    const Color expected = {90, 90, 90, 255};
-    // this is handwavy, but the precison loss scaled by 255 (8-bit per
-    // channel) should be less than one
-    const uint8_t tolerance = 1;
+    half3 expected = color;
     mat3 matrix;
     matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11;
     matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11;
     matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11;
+
+    // degamma before applying the matrix
+    if (mColorManagementUsed) {
+        ColorTransformHelper::DegammaColor(expected);
+    }
+
+    ColorTransformHelper::applyMatrix(expected, matrix);
+
+    if (mColorManagementUsed) {
+        ColorTransformHelper::GammaColor(expected);
+    }
+
+    const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+                                 uint8_t(expected.b * 255), 255};
+
+    // this is handwavy, but the precison loss scaled by 255 (8-bit per
+    // channel) should be less than one
+    const uint8_t tolerance = 1;
+
     Transaction().setColor(colorLayer, color)
         .setColorTransform(colorLayer, matrix, vec3()).apply();
     {
         SCOPED_TRACE("new color");
-        screenshot()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
+        screenshot()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
     }
 }
 
+class ExpectedResult {
+public:
+    enum Transaction {
+        NOT_PRESENTED = 0,
+        PRESENTED,
+    };
+
+    enum Buffer {
+        NOT_ACQUIRED = 0,
+        ACQUIRED,
+    };
+
+    enum PreviousBuffer {
+        NOT_RELEASED = 0,
+        RELEASED,
+    };
+
+    void reset() {
+        mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+        mExpectedSurfaceResults.clear();
+    }
+
+    void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer,
+                    ExpectedResult::Buffer bufferResult = NOT_ACQUIRED,
+                    ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+        mTransactionResult = transactionResult;
+        mExpectedSurfaceResults.emplace(std::piecewise_construct,
+                                        std::forward_as_tuple(layer->getHandle()),
+                                        std::forward_as_tuple(bufferResult, previousBufferResult));
+    }
+
+    void addSurfaces(ExpectedResult::Transaction transactionResult,
+                     const std::vector<sp<SurfaceControl>>& layers,
+                     ExpectedResult::Buffer bufferResult = NOT_ACQUIRED,
+                     ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+        for (const auto& layer : layers) {
+            addSurface(transactionResult, layer, bufferResult, previousBufferResult);
+        }
+    }
+
+    void verifyTransactionStats(const TransactionStats& transactionStats) const {
+        const auto& [latchTime, presentTime, surfaceStats] = transactionStats;
+        if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
+            ASSERT_GE(latchTime, 0) << "bad latch time";
+            ASSERT_GE(presentTime, 0) << "bad present time";
+        } else {
+            ASSERT_EQ(presentTime, -1) << "transaction shouldn't have been presented";
+            ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
+        }
+
+        ASSERT_EQ(surfaceStats.size(), mExpectedSurfaceResults.size())
+                << "wrong number of surfaces";
+
+        for (const auto& stats : surfaceStats) {
+            const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl);
+            ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end())
+                    << "unexpected surface control";
+            expectedSurfaceResult->second.verifySurfaceStats(stats, latchTime);
+        }
+    }
+
+private:
+    class ExpectedSurfaceResult {
+    public:
+        ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult,
+                              ExpectedResult::PreviousBuffer previousBufferResult)
+              : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
+
+        void verifySurfaceStats(const SurfaceStats& surfaceStats, nsecs_t latchTime) const {
+            const auto& [surfaceControl, acquireTime, releasePreviousBuffer] = surfaceStats;
+
+            ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
+                    << "bad acquire time";
+            ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
+            ASSERT_EQ(releasePreviousBuffer,
+                      mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED)
+                    << "bad previous buffer released";
+        }
+
+    private:
+        ExpectedResult::Buffer mBufferResult;
+        ExpectedResult::PreviousBuffer mPreviousBufferResult;
+    };
+
+    struct IBinderHash {
+        std::size_t operator()(const sp<IBinder>& strongPointer) const {
+            return std::hash<IBinder*>{}(strongPointer.get());
+        }
+    };
+    ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+    std::unordered_map<sp<IBinder>, ExpectedSurfaceResult, IBinderHash> mExpectedSurfaceResults;
+};
+
+class CallbackHelper {
+public:
+    static void function(void* callbackContext, const TransactionStats& transactionStats) {
+        if (!callbackContext) {
+            ALOGE("failed to get callback context");
+        }
+        CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext);
+        std::lock_guard lock(helper->mMutex);
+        helper->mTransactionStatsQueue.push(transactionStats);
+        helper->mConditionVariable.notify_all();
+    }
+
+    void getTransactionStats(TransactionStats* outStats) {
+        std::unique_lock lock(mMutex);
+
+        if (mTransactionStatsQueue.empty()) {
+            ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)),
+                      std::cv_status::timeout)
+                    << "did not receive callback";
+        }
+
+        *outStats = std::move(mTransactionStatsQueue.front());
+        mTransactionStatsQueue.pop();
+    }
+
+    void verifyFinalState() {
+        // Wait to see if there are extra callbacks
+        std::this_thread::sleep_for(500ms);
+
+        std::lock_guard lock(mMutex);
+        EXPECT_EQ(mTransactionStatsQueue.size(), 0) << "extra callbacks received";
+        mTransactionStatsQueue = {};
+    }
+
+    void* getContext() { return static_cast<void*>(this); }
+
+    std::mutex mMutex;
+    std::condition_variable mConditionVariable;
+    std::queue<TransactionStats> mTransactionStatsQueue;
+};
+
+class LayerCallbackTest : public LayerTransactionTest {
+protected:
+    virtual sp<SurfaceControl> createBufferStateLayer() {
+        return createLayer(mClient, "test", mWidth, mHeight,
+                           ISurfaceComposerClient::eFXSurfaceBufferState);
+    }
+
+    virtual void fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
+                                 const sp<SurfaceControl>& layer = nullptr) {
+        if (layer) {
+            sp<GraphicBuffer> buffer =
+                    new GraphicBuffer(mWidth, mHeight, PIXEL_FORMAT_RGBA_8888, 1,
+                                      BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                              BufferUsage::COMPOSER_OVERLAY |
+                                              BufferUsage::GPU_TEXTURE,
+                                      "test");
+            fillGraphicBufferColor(buffer, Rect(0, 0, mWidth, mHeight), Color::RED);
+
+            sp<Fence> fence = new Fence(-1);
+
+            transaction.setBuffer(layer, buffer)
+                    .setAcquireFence(layer, fence)
+                    .setSize(layer, mWidth, mHeight);
+        }
+
+        transaction.addTransactionCompletedCallback(callbackHelper->function,
+                                                    callbackHelper->getContext());
+    }
+
+    void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+                         bool finalState = false) {
+        TransactionStats transactionStats;
+        ASSERT_NO_FATAL_FAILURE(helper.getTransactionStats(&transactionStats));
+        EXPECT_NO_FATAL_FAILURE(expectedResult.verifyTransactionStats(transactionStats));
+
+        if (finalState) {
+            ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+        }
+    }
+
+    void waitForCallbacks(CallbackHelper& helper,
+                          const std::vector<ExpectedResult>& expectedResults,
+                          bool finalState = false) {
+        for (const auto& expectedResult : expectedResults) {
+            waitForCallback(helper, expectedResult);
+        }
+        if (finalState) {
+            ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+        }
+    }
+
+    uint32_t mWidth = 32;
+    uint32_t mHeight = 32;
+};
+
+TEST_F(LayerCallbackTest, Basic) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    fillTransaction(transaction, &callback, layer);
+
+    transaction.apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoBuffer) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    fillTransaction(transaction, &callback);
+
+    transaction.setPosition(layer, mWidth, mHeight).apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoStateChange) {
+    Transaction transaction;
+    CallbackHelper callback;
+    fillTransaction(transaction, &callback);
+
+    transaction.apply();
+
+    ExpectedResult expected;
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, OffScreen) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    fillTransaction(transaction, &callback, layer);
+
+    transaction.setPosition(layer, -100, -100).apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge) {
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    fillTransaction(transaction1, &callback1, layer1);
+    fillTransaction(transaction2, &callback2, layer2);
+
+    transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SameCallback) {
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback;
+    fillTransaction(transaction1, &callback, layer1);
+    fillTransaction(transaction2, &callback, layer2);
+
+    transaction2.merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SameLayer) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    fillTransaction(transaction1, &callback1, layer);
+    fillTransaction(transaction2, &callback2, layer);
+
+    transaction2.merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SingleBuffer) {
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    fillTransaction(transaction1, &callback1, layer1);
+    fillTransaction(transaction2, &callback2);
+
+    transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_DifferentClients) {
+    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+            client2(new SurfaceComposerClient);
+
+    ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+    ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    fillTransaction(transaction1, &callback1, layer1);
+    fillTransaction(transaction2, &callback2, layer2);
+
+    transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    for (size_t i = 0; i < 10; i++) {
+        fillTransaction(transaction, &callback, layer);
+
+        transaction.apply();
+
+        ExpectedResult expected;
+        expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+                            ExpectedResult::Buffer::NOT_ACQUIRED,
+                            (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+                                     : ExpectedResult::PreviousBuffer::RELEASED);
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+    }
+    ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    for (size_t i = 0; i < 10; i++) {
+        ExpectedResult expected;
+
+        if (i == 0) {
+            fillTransaction(transaction, &callback, layer);
+            expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+        } else {
+            fillTransaction(transaction, &callback);
+        }
+
+        transaction.apply();
+
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+    }
+    ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    for (size_t i = 0; i < 10; i++) {
+        if (i == 0) {
+            fillTransaction(transaction, &callback, layer);
+        } else {
+            fillTransaction(transaction, &callback);
+        }
+
+        transaction.setPosition(layer, mWidth, mHeight).apply();
+
+        ExpectedResult expected;
+        expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED
+                                     : ExpectedResult::Transaction::NOT_PRESENTED,
+                            layer);
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, i == 0));
+    }
+    ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge) {
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    for (size_t i = 0; i < 10; i++) {
+        fillTransaction(transaction1, &callback1, layer1);
+        fillTransaction(transaction2, &callback2, layer2);
+
+        transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+        ExpectedResult expected;
+        expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+                             ExpectedResult::Buffer::NOT_ACQUIRED,
+                             (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+                                      : ExpectedResult::PreviousBuffer::RELEASED);
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+    }
+    ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+    ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
+    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+            client2(new SurfaceComposerClient);
+    ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+    ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    for (size_t i = 0; i < 10; i++) {
+        fillTransaction(transaction1, &callback1, layer1);
+        fillTransaction(transaction2, &callback2, layer2);
+
+        transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+        ExpectedResult expected;
+        expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+                             ExpectedResult::Buffer::NOT_ACQUIRED,
+                             (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+                                      : ExpectedResult::PreviousBuffer::RELEASED);
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+    }
+    ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+    ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) {
+    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+            client2(new SurfaceComposerClient);
+    ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+    ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+
+    // Normal call to set up test
+    fillTransaction(transaction1, &callback1, layer1);
+    fillTransaction(transaction2, &callback2, layer2);
+
+    transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+    expected.reset();
+
+    // Test
+    fillTransaction(transaction1, &callback1);
+    fillTransaction(transaction2, &callback2);
+
+    transaction2.merge(std::move(transaction1)).apply();
+
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) {
+    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+            client2(new SurfaceComposerClient);
+
+    ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+    ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+
+    // Normal call to set up test
+    fillTransaction(transaction1, &callback1, layer1);
+    fillTransaction(transaction2, &callback2, layer2);
+
+    transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+    expected.reset();
+
+    // Test
+    fillTransaction(transaction1, &callback1);
+    fillTransaction(transaction2, &callback2);
+
+    transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+    expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    std::vector<ExpectedResult> expectedResults(50);
+    ExpectedResult::PreviousBuffer previousBufferResult =
+            ExpectedResult::PreviousBuffer::NOT_RELEASED;
+    for (auto& expected : expectedResults) {
+        expected.reset();
+        expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+                            ExpectedResult::Buffer::NOT_ACQUIRED, previousBufferResult);
+        previousBufferResult = ExpectedResult::PreviousBuffer::RELEASED;
+
+        fillTransaction(transaction, &callback, layer);
+
+        transaction.apply();
+        std::this_thread::sleep_for(200ms);
+    }
+    EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    std::vector<ExpectedResult> expectedResults(50);
+    bool first = true;
+    for (auto& expected : expectedResults) {
+        expected.reset();
+
+        if (first) {
+            fillTransaction(transaction, &callback, layer);
+            expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+            first = false;
+        } else {
+            fillTransaction(transaction, &callback);
+        }
+
+        transaction.apply();
+        std::this_thread::sleep_for(200ms);
+    }
+    EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    // Normal call to set up test
+    Transaction transaction;
+    CallbackHelper callback;
+    fillTransaction(transaction, &callback, layer);
+
+    transaction.setPosition(layer, mWidth, mHeight).apply();
+
+    ExpectedResult expectedResult;
+    expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expectedResult, true));
+
+    // Test
+    std::vector<ExpectedResult> expectedResults(50);
+    for (auto& expected : expectedResults) {
+        expected.reset();
+        expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer);
+
+        fillTransaction(transaction, &callback);
+
+        transaction.setPosition(layer, mWidth, mHeight).apply();
+
+        std::this_thread::sleep_for(200ms);
+    }
+    EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
 class LayerUpdateTest : public LayerTransactionTest {
 protected:
     virtual void SetUp() {
@@ -2557,6 +3252,37 @@
     }
 }
 
+TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) {
+    sp<SurfaceControl> mGrandChild =
+        mClient->createSurface(String8("Grand Child"), 10, 10,
+                PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+    fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
+
+    {
+        SCOPED_TRACE("Grandchild visible");
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->checkPixel(64, 64, 111, 111, 111);
+    }
+
+    mChild->clear();
+
+    {
+        SCOPED_TRACE("After destroying child");
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->expectFGColor(64, 64);
+    }
+
+    asTransaction([&](Transaction& t) {
+         t.reparent(mGrandChild, mFGSurfaceControl->getHandle());
+    });
+
+    {
+        SCOPED_TRACE("After reparenting grandchild");
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->checkPixel(64, 64, 111, 111, 111);
+    }
+}
+
 TEST_F(ChildLayerTest, DetachChildrenSameClient) {
     asTransaction([&](Transaction& t) {
         t.show(mChild);
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index f71f1ea..d24c0de 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -37,6 +37,7 @@
 #include "mock/MockEventThread.h"
 #include "mock/MockMessageQueue.h"
 #include "mock/RenderEngine/MockRenderEngine.h"
+#include "mock/system/window/MockNativeWindow.h"
 
 namespace android {
 namespace {
@@ -45,6 +46,7 @@
 using testing::AtLeast;
 using testing::ByMove;
 using testing::DoAll;
+using testing::Invoke;
 using testing::IsNull;
 using testing::Mock;
 using testing::NotNull;
@@ -65,6 +67,7 @@
 constexpr hwc2_layer_t HWC_LAYER = 5000;
 constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
 
+constexpr DisplayId DEFAULT_DISPLAY_ID = 42;
 constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
 constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
 
@@ -91,6 +94,10 @@
         EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
         EXPECT_CALL(*mPrimaryDispSync, getPeriod())
                 .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+        EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
+        EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
 
         mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
         setupComposer(0);
@@ -137,7 +144,10 @@
     sp<DisplayDevice> mDisplay;
     sp<DisplayDevice> mExternalDisplay;
     sp<mock::DisplaySurface> mDisplaySurface = new mock::DisplaySurface();
-    renderengine::mock::Surface* mRenderSurface = new renderengine::mock::Surface();
+    mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
+
+    sp<GraphicBuffer> mBuffer = new GraphicBuffer();
+    ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
 
     mock::EventThread* mEventThread = new mock::EventThread();
     mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
@@ -190,7 +200,8 @@
     constexpr bool forSystem = true;
 
     DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH,
-                                 DEFAULT_DISPLAY_HEIGHT, ui::Transform::ROT_0);
+                                 DEFAULT_DISPLAY_HEIGHT, ui::Dataspace::V0_SRGB,
+                                 ui::Transform::ROT_0);
 
     auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
         return mFlinger.traverseLayersInDisplay(mDisplay, visitor);
@@ -225,16 +236,20 @@
     static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
 
     static void setupPreconditions(CompositionTest* test) {
-        FakeHwcDisplayInjector(DisplayDevice::DISPLAY_PRIMARY, HWC2::DisplayType::Physical)
+        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
+        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
+
+        FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, HWC2::DisplayType::Physical,
+                               true /* isPrimary */)
                 .setCapabilities(&test->mDefaultCapabilities)
                 .inject(&test->mFlinger, test->mComposer);
 
-        test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DisplayDevice::DISPLAY_PRIMARY,
-                                                   DisplayDevice::DISPLAY_PRIMARY)
-                                 .setDisplaySize(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT)
+        test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
+                                                   false /* isVirtual */, true /* isPrimary */)
                                  .setDisplaySurface(test->mDisplaySurface)
-                                 .setRenderSurface(std::unique_ptr<renderengine::Surface>(
-                                         test->mRenderSurface))
+                                 .setNativeWindow(test->mNativeWindow)
                                  .setSecure(Derived::IS_SECURE)
                                  .setPowerMode(Derived::INIT_POWER_MODE)
                                  .inject();
@@ -256,13 +271,9 @@
         EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
         EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
 
-        EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
-                .WillOnce(Return(true));
-        EXPECT_CALL(*test->mRenderEngine,
-                    setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
-                                             Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
-                                             ui::Transform::ROT_0))
-                .Times(1);
+        EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() {
+            return base::unique_fd(0);
+        }));
 
         EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
         EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
@@ -288,7 +299,7 @@
         EXPECT_CALL(*test->mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd())));
         EXPECT_CALL(*test->mRenderEngine, finish()).WillOnce(Return(true));
 
-        EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::SRGB)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(_)).Times(1);
         EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
                 .Times(1);
         // This expectation retires on saturation as setViewportAndProjection is
@@ -313,8 +324,6 @@
 
     static void setupHwcCompositionCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)).Times(1);
-
-        EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
     }
 
     static void setupRECompositionCallExpectations(CompositionTest* test) {
@@ -334,12 +343,18 @@
                     setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
                                              Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                                              ui::Transform::ROT_0))
-                .Times(1)
-                .RetiresOnSaturation();
-        EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
-                .WillOnce(Return(true))
-                .RetiresOnSaturation();
-        EXPECT_CALL(*test->mRenderSurface, swapBuffers()).Times(1);
+                .Times(1);
+        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull())).WillOnce(Return(true));
+        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull())).WillOnce(Return(true));
+        EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
+                .WillOnce(Return(
+                        ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer))));
+        EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1);
+        EXPECT_CALL(*test->mNativeWindow, queueBuffer(_, _)).WillOnce(Return(0));
+        EXPECT_CALL(*test->mNativeWindow, dequeueBuffer(_, _))
+                .WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1),
+                                Return(0)));
     }
 
     template <typename Case>
@@ -552,10 +567,6 @@
                                   IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
                 .Times(1);
 
-        // TODO: ColorLayer::onPreComposition() always returns true, triggering an
-        // extra layer update in SurfaceFlinger::preComposition(). This seems
-        // wrong on the surface.
-        EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
     }
 
     static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
@@ -748,7 +759,9 @@
         EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
                 .WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
 
-        layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), test->mDisplay->getId());
+        const auto displayId = test->mDisplay->getId();
+        ASSERT_TRUE(displayId);
+        layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), *displayId);
 
         Mock::VerifyAndClear(test->mComposer);
 
@@ -761,8 +774,10 @@
     static void cleanupInjectedLayers(CompositionTest* test) {
         EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
                 .WillOnce(Return(Error::NONE));
+        const auto displayId = test->mDisplay->getId();
+        ASSERT_TRUE(displayId);
         for (auto layer : test->mFlinger.mutableDrawingState().layersSortedByZ) {
-            layer->destroyHwcLayer(test->mDisplay->getId());
+            layer->destroyHwcLayer(*displayId);
         }
         test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
     }
@@ -953,7 +968,7 @@
 
 struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
     static void setupLayerState(CompositionTest*, sp<Layer> layer) {
-        layer->forceClientComposition(DisplayDevice::DISPLAY_PRIMARY);
+        layer->forceClientComposition(DEFAULT_DISPLAY_ID);
     }
 
     template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index 4f1c99e..55995d0 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -68,32 +68,44 @@
 
 } // namespace
 
+const DisplayIdentificationData& getInternalEdid() {
+    static const DisplayIdentificationData data = asDisplayIdentificationData(kInternalEdid);
+    return data;
+}
+
+const DisplayIdentificationData& getExternalEdid() {
+    static const DisplayIdentificationData data = asDisplayIdentificationData(kExternalEdid);
+    return data;
+}
+
+const DisplayIdentificationData& getExternalEedid() {
+    static const DisplayIdentificationData data = asDisplayIdentificationData(kExternalEedid);
+    return data;
+}
+
 TEST(DisplayIdentificationTest, isEdid) {
     EXPECT_FALSE(isEdid({}));
 
-    EXPECT_TRUE(isEdid(asDisplayIdentificationData(kInternalEdid)));
-    EXPECT_TRUE(isEdid(asDisplayIdentificationData(kExternalEdid)));
-    EXPECT_TRUE(isEdid(asDisplayIdentificationData(kExternalEedid)));
+    EXPECT_TRUE(isEdid(getInternalEdid()));
+    EXPECT_TRUE(isEdid(getExternalEdid()));
+    EXPECT_TRUE(isEdid(getExternalEedid()));
 }
 
 TEST(DisplayIdentificationTest, parseEdid) {
-    auto data = asDisplayIdentificationData(kInternalEdid);
-    auto edid = parseEdid(data);
+    auto edid = parseEdid(getInternalEdid());
     ASSERT_TRUE(edid);
     EXPECT_EQ(0x4ca3u, edid->manufacturerId);
     EXPECT_STREQ("SEC", edid->pnpId.data());
     // ASCII text should be used as fallback if display name and serial number are missing.
     EXPECT_EQ("121AT11-801", edid->displayName);
 
-    data = asDisplayIdentificationData(kExternalEdid);
-    edid = parseEdid(data);
+    edid = parseEdid(getExternalEdid());
     ASSERT_TRUE(edid);
     EXPECT_EQ(0x22f0u, edid->manufacturerId);
     EXPECT_STREQ("HWP", edid->pnpId.data());
     EXPECT_EQ("HP ZR30w", edid->displayName);
 
-    data = asDisplayIdentificationData(kExternalEedid);
-    edid = parseEdid(data);
+    edid = parseEdid(getExternalEedid());
     ASSERT_TRUE(edid);
     EXPECT_EQ(0x4c2du, edid->manufacturerId);
     EXPECT_STREQ("SAM", edid->pnpId.data());
@@ -105,7 +117,7 @@
     EXPECT_FALSE(parseEdid({}));
 
     // Display name must be printable.
-    auto data = asDisplayIdentificationData(kExternalEdid);
+    auto data = getExternalEdid();
     data[97] = '\x1b';
     auto edid = parseEdid(data);
     ASSERT_TRUE(edid);
@@ -128,20 +140,32 @@
     EXPECT_STREQ("SAM", getPnpId(0x4c2du).value_or(PnpId{}).data());
 }
 
-TEST(DisplayIdentificationTest, generateDisplayId) {
-    const auto primaryId = generateDisplayId(0, asDisplayIdentificationData(kInternalEdid));
-    ASSERT_TRUE(primaryId);
+TEST(DisplayIdentificationTest, parseDisplayIdentificationData) {
+    const auto primaryInfo = parseDisplayIdentificationData(0, getInternalEdid());
+    ASSERT_TRUE(primaryInfo);
 
-    const auto secondaryId = generateDisplayId(1, asDisplayIdentificationData(kExternalEdid));
-    ASSERT_TRUE(secondaryId);
+    const auto secondaryInfo = parseDisplayIdentificationData(1, getExternalEdid());
+    ASSERT_TRUE(secondaryInfo);
 
-    const auto tertiaryId = generateDisplayId(2, asDisplayIdentificationData(kExternalEedid));
-    ASSERT_TRUE(tertiaryId);
+    const auto tertiaryInfo = parseDisplayIdentificationData(2, getExternalEedid());
+    ASSERT_TRUE(tertiaryInfo);
 
     // Display IDs should be unique.
-    EXPECT_NE(primaryId, secondaryId);
-    EXPECT_NE(primaryId, tertiaryId);
-    EXPECT_NE(secondaryId, tertiaryId);
+    EXPECT_NE(primaryInfo->id, secondaryInfo->id);
+    EXPECT_NE(primaryInfo->id, tertiaryInfo->id);
+    EXPECT_NE(secondaryInfo->id, tertiaryInfo->id);
+}
+
+TEST(DisplayIdentificationTest, getFallbackDisplayId) {
+    // Manufacturer ID should be invalid.
+    ASSERT_FALSE(getPnpId(getFallbackDisplayId(0)));
+    ASSERT_FALSE(getPnpId(getFallbackDisplayId(0xffu)));
+}
+
+TEST(DisplayIdentificationTest, getVirtualDisplayId) {
+    // Manufacturer ID should be invalid.
+    ASSERT_FALSE(getPnpId(getVirtualDisplayId(0)));
+    ASSERT_FALSE(getPnpId(getVirtualDisplayId(0xffff'ffffu)));
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.h
similarity index 69%
copy from services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h
copy to services/surfaceflinger/tests/unittests/DisplayIdentificationTest.h
index 6595466..1c8e5cc 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Framebuffer.h
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.h
@@ -16,19 +16,12 @@
 
 #pragma once
 
-#include <cstdint>
-
-struct ANativeWindowBuffer;
+#include "DisplayHardware/DisplayIdentification.h"
 
 namespace android {
-namespace renderengine {
 
-class Framebuffer {
-public:
-    virtual ~Framebuffer() = default;
+const DisplayIdentificationData& getInternalEdid();
+const DisplayIdentificationData& getExternalEdid();
+const DisplayIdentificationData& getExternalEedid();
 
-    virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) = 0;
-};
-
-}   // namespace renderengine
-}   // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index d32627a..aa1fc1a 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -17,12 +17,16 @@
 #undef LOG_TAG
 #define LOG_TAG "LibSurfaceFlingerUnittests"
 
+#include <type_traits>
+
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include <log/log.h>
 
 #include <ui/DebugUtils.h>
+
+#include "DisplayIdentificationTest.h"
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
 #include "mock/DisplayHardware/MockDisplaySurface.h"
@@ -75,9 +79,11 @@
 
 #define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true };
 
-BOOL_SUBSTITUTE(Critical);
 BOOL_SUBSTITUTE(Async);
+BOOL_SUBSTITUTE(Critical);
+BOOL_SUBSTITUTE(Primary);
 BOOL_SUBSTITUTE(Secure);
+BOOL_SUBSTITUTE(Virtual);
 
 /* ------------------------------------------------------------------------
  *
@@ -98,7 +104,7 @@
     // --------------------------------------------------------------------
     // Postcondition helpers
 
-    bool hasHwcDisplay(hwc2_display_t displayId);
+    bool hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId);
     bool hasTransactionFlagSet(int flag);
     bool hasDisplayDevice(sp<IBinder> displayToken);
     sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
@@ -113,6 +119,8 @@
     TestableSurfaceFlinger mFlinger;
     mock::EventThread* mEventThread = new mock::EventThread();
     mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
+    sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
+    sp<GraphicBuffer> mBuffer = new GraphicBuffer();
 
     // These mocks are created by the test, but are destroyed by SurfaceFlinger
     // by virtue of being stored into a std::unique_ptr. However we still need
@@ -127,8 +135,6 @@
     sp<mock::GraphicBufferConsumer> mConsumer;
     sp<mock::GraphicBufferProducer> mProducer;
     surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
-    sp<mock::NativeWindow> mNativeWindow;
-    renderengine::mock::Surface* mRenderSurface = nullptr;
 };
 
 DisplayTransactionTest::DisplayTransactionTest() {
@@ -197,15 +203,14 @@
     ASSERT_TRUE(mNativeWindowSurface == nullptr);
 
     mNativeWindowSurface = new surfaceflinger::mock::NativeWindowSurface();
-    mNativeWindow = new mock::NativeWindow();
 
     mFlinger.setCreateNativeWindowSurface([this](auto) {
         return std::unique_ptr<surfaceflinger::NativeWindowSurface>(mNativeWindowSurface);
     });
 }
 
-bool DisplayTransactionTest::hasHwcDisplay(hwc2_display_t displayId) {
-    return mFlinger.mutableHwcDisplaySlots().count(displayId) == 1;
+bool DisplayTransactionTest::hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId) {
+    return mFlinger.mutableHwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1;
 }
 
 bool DisplayTransactionTest::hasTransactionFlagSet(int flag) {
@@ -240,20 +245,67 @@
  *
  */
 
-template <DisplayDevice::DisplayType type, DisplayDevice::DisplayType displayId, int width,
-          int height, Critical critical, Async async, Secure secure, int grallocUsage>
+template <typename PhysicalDisplay>
+struct PhysicalDisplayId {};
+
+template <DisplayId displayId>
+using VirtualDisplayId = std::integral_constant<DisplayId, displayId>;
+
+struct NoDisplayId {};
+
+template <typename>
+struct IsPhysicalDisplayId : std::bool_constant<false> {};
+
+template <typename PhysicalDisplay>
+struct IsPhysicalDisplayId<PhysicalDisplayId<PhysicalDisplay>> : std::bool_constant<true> {};
+
+template <typename>
+struct DisplayIdGetter;
+
+template <typename PhysicalDisplay>
+struct DisplayIdGetter<PhysicalDisplayId<PhysicalDisplay>> {
+    static std::optional<DisplayId> get() {
+        if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
+            return getFallbackDisplayId(static_cast<bool>(PhysicalDisplay::PRIMARY)
+                                                ? HWC_DISPLAY_PRIMARY
+                                                : HWC_DISPLAY_EXTERNAL);
+        }
+
+        const auto info =
+                parseDisplayIdentificationData(PhysicalDisplay::PORT,
+                                               PhysicalDisplay::GET_IDENTIFICATION_DATA());
+        return info ? std::make_optional(info->id) : std::nullopt;
+    }
+};
+
+template <DisplayId displayId>
+struct DisplayIdGetter<VirtualDisplayId<displayId>> {
+    static std::optional<DisplayId> get() { return displayId; }
+};
+
+template <>
+struct DisplayIdGetter<NoDisplayId> {
+    static std::optional<DisplayId> get() { return {}; }
+};
+
+// DisplayIdType can be:
+//     1) PhysicalDisplayId<...> for generated ID of physical display backed by HWC.
+//     2) VirtualDisplayId<...> for hard-coded ID of virtual display backed by HWC.
+//     3) NoDisplayId for virtual display without HWC backing.
+template <typename DisplayIdType, int width, int height, Critical critical, Async async,
+          Secure secure, Primary primary, int grallocUsage>
 struct DisplayVariant {
+    using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
+
     // The display width and height
     static constexpr int WIDTH = width;
     static constexpr int HEIGHT = height;
 
     static constexpr int GRALLOC_USAGE = grallocUsage;
 
-    // The type for this display
-    static constexpr DisplayDevice::DisplayType TYPE = type;
-    static_assert(TYPE != DisplayDevice::DISPLAY_ID_INVALID);
-
-    static constexpr DisplayDevice::DisplayType DISPLAY_ID = displayId;
+    // Whether the display is virtual or physical
+    static constexpr Virtual VIRTUAL =
+            IsPhysicalDisplayId<DisplayIdType>{} ? Virtual::FALSE : Virtual::TRUE;
 
     // When creating native window surfaces for the framebuffer, whether those should be critical
     static constexpr Critical CRITICAL = critical;
@@ -264,9 +316,23 @@
     // Whether the display should be treated as secure
     static constexpr Secure SECURE = secure;
 
+    // Whether the display is primary
+    static constexpr Primary PRIMARY = primary;
+
     static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
-        auto injector = FakeDisplayDeviceInjector(test->mFlinger, TYPE, DISPLAY_ID);
+        auto injector =
+                FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
+                                          static_cast<bool>(VIRTUAL), static_cast<bool>(PRIMARY));
+
         injector.setSecure(static_cast<bool>(SECURE));
+        injector.setNativeWindow(test->mNativeWindow);
+
+        // Creating a DisplayDevice requires getting default dimensions from the
+        // native window.
+        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
+        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
         return injector;
     }
 
@@ -274,20 +340,11 @@
     static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
         EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow())
                 .WillOnce(Return(test->mNativeWindow));
-        EXPECT_CALL(*test->mNativeWindow, perform(19)).WillRepeatedly(Return(NO_ERROR));
 
-        // For simplicity, we only expect to create a single render surface for
-        // each test.
-        ASSERT_TRUE(test->mRenderSurface == nullptr);
-        test->mRenderSurface = new renderengine::mock::Surface();
-        EXPECT_CALL(*test->mRenderEngine, createSurface())
-                .WillOnce(Return(ByMove(
-                        std::unique_ptr<renderengine::Surface>(test->mRenderSurface))));
-        EXPECT_CALL(*test->mRenderSurface, setAsync(static_cast<bool>(ASYNC))).Times(1);
-        EXPECT_CALL(*test->mRenderSurface, setCritical(static_cast<bool>(CRITICAL))).Times(1);
-        EXPECT_CALL(*test->mRenderSurface, setNativeWindow(test->mNativeWindow.get())).Times(1);
-        EXPECT_CALL(*test->mRenderSurface, getWidth()).WillOnce(Return(WIDTH));
-        EXPECT_CALL(*test->mRenderSurface, getHeight()).WillOnce(Return(HEIGHT));
+        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
+        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
     }
 
     static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
@@ -306,7 +363,8 @@
     }
 };
 
-template <hwc2_display_t hwcDisplayId, HWC2::DisplayType hwcDisplayType, typename DisplayVariant>
+template <hwc2_display_t hwcDisplayId, HWC2::DisplayType hwcDisplayType, typename DisplayVariant,
+          typename PhysicalDisplay = void>
 struct HwcDisplayVariant {
     // The display id supplied by the HWC
     static constexpr hwc2_display_t HWC_DISPLAY_ID = hwcDisplayId;
@@ -325,7 +383,10 @@
 
     // Called by tests to inject a HWC display setup
     static void injectHwcDisplay(DisplayTransactionTest* test) {
-        FakeHwcDisplayInjector(DisplayVariant::TYPE, HWC_DISPLAY_TYPE)
+        const auto displayId = DisplayVariant::DISPLAY_ID::get();
+        ASSERT_TRUE(displayId);
+        FakeHwcDisplayInjector(*displayId, HWC_DISPLAY_TYPE,
+                               static_cast<bool>(DisplayVariant::PRIMARY))
                 .setHwcDisplayId(HWC_DISPLAY_ID)
                 .setWidth(DisplayVariant::WIDTH)
                 .setHeight(DisplayVariant::HEIGHT)
@@ -362,8 +423,16 @@
                     getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
                                         IComposerClient::Attribute::DPI_Y, _))
                 .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
-                .WillRepeatedly(Return(Error::UNSUPPORTED));
+
+        if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
+            EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+                    .WillOnce(DoAll(SetArgPointee<1>(PhysicalDisplay::PORT),
+                                    SetArgPointee<2>(PhysicalDisplay::GET_IDENTIFICATION_DATA()),
+                                    Return(Error::NONE)));
+        } else {
+            EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+                    .WillOnce(Return(Error::UNSUPPORTED));
+        }
     }
 
     // Called by tests to set up HWC call expectations
@@ -373,50 +442,67 @@
     }
 };
 
-struct NonHwcDisplayVariant {
-    static void injectHwcDisplay(DisplayTransactionTest*) {}
-
-    static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
-    }
-};
-
 // Physical displays are expected to be synchronous, secure, and have a HWC display for output.
 constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
         GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
 
-template <hwc2_display_t hwcDisplayId, DisplayDevice::DisplayType type, int width, int height,
+template <hwc2_display_t hwcDisplayId, typename PhysicalDisplay, int width, int height,
           Critical critical>
 struct PhysicalDisplayVariant
-      : public DisplayVariant<type, type, width, height, critical, Async::FALSE, Secure::TRUE,
-                              GRALLOC_USAGE_PHYSICAL_DISPLAY>,
-        public HwcDisplayVariant<hwcDisplayId, HWC2::DisplayType::Physical,
-                                 DisplayVariant<type, type, width, height, critical, Async::FALSE,
-                                                Secure::TRUE, GRALLOC_USAGE_PHYSICAL_DISPLAY>> {};
+      : DisplayVariant<PhysicalDisplayId<PhysicalDisplay>, width, height, critical, Async::FALSE,
+                       Secure::TRUE, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+        HwcDisplayVariant<hwcDisplayId, HWC2::DisplayType::Physical,
+                          DisplayVariant<PhysicalDisplayId<PhysicalDisplay>, width, height,
+                                         critical, Async::FALSE, Secure::TRUE,
+                                         PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+                          PhysicalDisplay> {};
+
+template <bool hasIdentificationData>
+struct PrimaryDisplay {
+    static constexpr Primary PRIMARY = Primary::TRUE;
+    static constexpr uint8_t PORT = 255;
+    static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
+    static constexpr auto GET_IDENTIFICATION_DATA = getInternalEdid;
+};
+
+template <bool hasIdentificationData>
+struct ExternalDisplay {
+    static constexpr Primary PRIMARY = Primary::FALSE;
+    static constexpr uint8_t PORT = 254;
+    static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
+    static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
+};
+
+struct TertiaryDisplay {
+    static constexpr Primary PRIMARY = Primary::FALSE;
+};
 
 // A primary display is a physical display that is critical
 using PrimaryDisplayVariant =
-        PhysicalDisplayVariant<1001, DisplayDevice::DISPLAY_PRIMARY, 3840, 2160, Critical::TRUE>;
+        PhysicalDisplayVariant<1001, PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
 
 // An external display is physical display that is not critical.
 using ExternalDisplayVariant =
-        PhysicalDisplayVariant<1002, DisplayDevice::DISPLAY_EXTERNAL, 1920, 1280, Critical::FALSE>;
+        PhysicalDisplayVariant<1002, ExternalDisplay<false>, 1920, 1280, Critical::FALSE>;
 
 using TertiaryDisplayVariant =
-        PhysicalDisplayVariant<1003, DisplayDevice::DISPLAY_EXTERNAL, 1600, 1200, Critical::FALSE>;
+        PhysicalDisplayVariant<1003, TertiaryDisplay, 1600, 1200, Critical::FALSE>;
 
 // A virtual display not supported by the HWC.
 constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0;
 
 template <int width, int height, Secure secure>
 struct NonHwcVirtualDisplayVariant
-      : public DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_ID_INVALID,
-                              width, height, Critical::FALSE, Async::TRUE, secure,
-                              GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>,
-        public NonHwcDisplayVariant {
-    using Base = DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_ID_INVALID,
-                                width, height, Critical::FALSE, Async::TRUE, secure,
-                                GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
+      : DisplayVariant<NoDisplayId, width, height, Critical::FALSE, Async::TRUE, secure,
+                       Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY> {
+    using Base = DisplayVariant<NoDisplayId, width, height, Critical::FALSE, Async::TRUE, secure,
+                                Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
+
+    static void injectHwcDisplay(DisplayTransactionTest*) {}
+
+    static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
+    }
 
     static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
         Base::setupNativeWindowSurfaceCreationCallExpectations(test);
@@ -429,14 +515,14 @@
 
 template <int width, int height, Secure secure>
 struct HwcVirtualDisplayVariant
-      : public DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_VIRTUAL, width,
-                              height, Critical::FALSE, Async::TRUE, secure,
-                              GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
-        public HwcDisplayVariant<1010, HWC2::DisplayType::Virtual,
-                                 NonHwcVirtualDisplayVariant<width, height, secure>> {
-    using Base =
-            DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_VIRTUAL, width,
-                           height, Critical::FALSE, Async::TRUE, secure, GRALLOC_USAGE_HW_COMPOSER>;
+      : DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE, secure,
+                       Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
+        HwcDisplayVariant<
+                1010, HWC2::DisplayType::Virtual,
+                DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE,
+                               secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> {
+    using Base = DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE,
+                                secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>;
     using Self = HwcVirtualDisplayVariant<width, height, secure>;
 
     static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
@@ -850,8 +936,8 @@
     // The display should have been added to the current state
     ASSERT_TRUE(hasCurrentDisplayState(displayToken));
     const auto& display = getCurrentDisplayState(displayToken);
-    EXPECT_EQ(DisplayDevice::DISPLAY_VIRTUAL, display.type);
-    EXPECT_EQ(false, display.isSecure);
+    EXPECT_TRUE(display.isVirtual());
+    EXPECT_FALSE(display.isSecure);
     EXPECT_EQ(name.string(), display.displayName);
 
     // --------------------------------------------------------------------
@@ -881,8 +967,8 @@
     // The display should have been added to the current state
     ASSERT_TRUE(hasCurrentDisplayState(displayToken));
     const auto& display = getCurrentDisplayState(displayToken);
-    EXPECT_EQ(DisplayDevice::DISPLAY_VIRTUAL, display.type);
-    EXPECT_EQ(true, display.isSecure);
+    EXPECT_TRUE(display.isVirtual());
+    EXPECT_TRUE(display.isSecure);
     EXPECT_EQ(name.string(), display.displayName);
 
     // --------------------------------------------------------------------
@@ -969,9 +1055,6 @@
     // The call disable vsyncs
     EXPECT_CALL(*mEventControlThread, setVsyncEnabled(false)).Times(1);
 
-    // The call clears the current render engine surface
-    EXPECT_CALL(*mRenderEngine, resetCurrentSurface());
-
     // The call ends any display resyncs
     EXPECT_CALL(*mPrimaryDispSync, endResync()).Times(1);
 
@@ -1002,9 +1085,12 @@
  */
 class GetBestColorModeTest : public DisplayTransactionTest {
 public:
+    static constexpr DisplayId DEFAULT_DISPLAY_ID = 777;
+
     GetBestColorModeTest()
           : DisplayTransactionTest(),
-            mInjector(FakeDisplayDeviceInjector(mFlinger, DisplayDevice::DISPLAY_PRIMARY, 0)) {}
+            mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, false /* isVirtual */,
+                                                true /* isPrimary */)) {}
 
     void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
 
@@ -1020,6 +1106,15 @@
     void getBestColorMode() {
         mInjector.setHwcColorModes(mHwcColorModes);
         mInjector.setHasWideColorGamut(mHasWideColorGamut);
+        mInjector.setNativeWindow(mNativeWindow);
+
+        // Creating a DisplayDevice requires getting default dimensions from the
+        // native window.
+        EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(1080 /* arbitrary */), Return(0)));
+        EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(1920 /* arbitrary */), Return(0)));
+        EXPECT_CALL(*mNativeWindow, perform(13)).Times(1);
         auto displayDevice = mInjector.inject();
 
         displayDevice->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
@@ -1127,18 +1222,22 @@
     // Invocation
 
     DisplayDeviceState state;
-    state.type = Case::Display::TYPE;
+    state.displayId = static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
+                                                                : Case::Display::DISPLAY_ID::get();
     state.isSecure = static_cast<bool>(Case::Display::SECURE);
 
-    auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::TYPE, state,
-                                                         displaySurface, producer);
+    auto device =
+            mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::DISPLAY_ID::get(),
+                                                   state, displaySurface, producer);
 
     // --------------------------------------------------------------------
     // Postconditions
 
     ASSERT_TRUE(device != nullptr);
-    EXPECT_EQ(Case::Display::TYPE, device->getDisplayType());
+    EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
+    EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
     EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
+    EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
     EXPECT_EQ(Case::Display::WIDTH, device->getWidth());
     EXPECT_EQ(Case::Display::HEIGHT, device->getHeight());
     EXPECT_EQ(Case::WideColorSupport::WIDE_COLOR_SUPPORTED, device->hasWideColorGamut());
@@ -1166,11 +1265,14 @@
 }
 
 TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) {
-    // We need to resize this so that the HWC thinks the virtual display
-    // is something it created.
-    mFlinger.mutableHwcDisplayData().resize(3);
+    using Case = HwcVirtualDisplayCase;
 
-    setupNewDisplayDeviceInternalTest<HwcVirtualDisplayCase>();
+    // Insert display data so that the HWC thinks it created the virtual display.
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(displayId);
+    mFlinger.mutableHwcDisplayData()[*displayId] = {};
+
+    setupNewDisplayDeviceInternalTest<Case>();
 }
 
 TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) {
@@ -1258,7 +1360,7 @@
 
     EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
     EXPECT_CALL(*mEventThread,
-                onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+                onHotplugReceived(static_cast<bool>(Case::Display::PRIMARY)
                                           ? EventThread::DisplayType::Primary
                                           : EventThread::DisplayType::External,
                                   true))
@@ -1269,7 +1371,7 @@
 void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
     EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
     EXPECT_CALL(*mEventThread,
-                onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+                onHotplugReceived(static_cast<bool>(Case::Display::PRIMARY)
                                           ? EventThread::DisplayType::Primary
                                           : EventThread::DisplayType::External,
                                   false))
@@ -1282,30 +1384,35 @@
     ASSERT_TRUE(hasDisplayDevice(displayToken));
     const auto& device = getDisplayDevice(displayToken);
     EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
-    EXPECT_EQ(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY, device->isPrimary());
+    EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
 
     // The display should have been set up in the current display state
     ASSERT_TRUE(hasCurrentDisplayState(displayToken));
     const auto& current = getCurrentDisplayState(displayToken);
-    EXPECT_EQ(Case::Display::TYPE, current.type);
+    EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
+    EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
+                                                        : Case::Display::DISPLAY_ID::get(),
+              current.displayId);
 
     // The display should have been set up in the drawing display state
     ASSERT_TRUE(hasDrawingDisplayState(displayToken));
     const auto& draw = getDrawingDisplayState(displayToken);
-    EXPECT_EQ(Case::Display::TYPE, draw.type);
+    EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
+    EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
+                                                        : Case::Display::DISPLAY_ID::get(),
+              draw.displayId);
 }
 
 template <typename Case>
 void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() {
     // HWComposer should have an entry for the display
-    EXPECT_TRUE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+    EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
 
-    // The display should be set up as a built-in display.
-    static_assert(0 <= Case::Display::TYPE &&
-                          Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
-                  "Must use a valid physical display type index for the fixed-size array");
-    auto& displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
-    ASSERT_TRUE(displayToken != nullptr);
+    // SF should have a display token.
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(displayId);
+    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 1);
+    auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[*displayId];
 
     verifyDisplayIsConnected<Case>(displayToken);
 }
@@ -1371,7 +1478,7 @@
     // Postconditions
 
     // HWComposer should not have an entry for the display
-    EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+    EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
 }
 
 template <typename Case>
@@ -1407,13 +1514,12 @@
     // Postconditions
 
     // HWComposer should not have an entry for the display
-    EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+    EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
 
-    // The display should not be set up as a built-in display.
-    ASSERT_TRUE(0 <= Case::Display::TYPE &&
-                Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
-    auto displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
-    EXPECT_TRUE(displayToken == nullptr);
+    // SF should not have a display token.
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(displayId);
+    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 0);
 
     // The existing token should have been removed
     verifyDisplayIsNotConnected(existing.token());
@@ -1500,13 +1606,12 @@
     // Postconditions
 
     // HWComposer should not have an entry for the display
-    EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+    EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
 
-    // The display should not be set up as a primary built-in display.
-    ASSERT_TRUE(0 <= Case::Display::TYPE &&
-                Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
-    auto displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
-    EXPECT_TRUE(displayToken == nullptr);
+    // SF should not have a display token.
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(displayId);
+    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 0);
 }
 
 TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) {
@@ -1545,10 +1650,10 @@
 
     // The existing token should have been removed
     verifyDisplayIsNotConnected(existing.token());
-    static_assert(0 <= Case::Display::TYPE &&
-                          Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
-                  "Display type must be a built-in display");
-    EXPECT_NE(existing.token(), mFlinger.mutableDisplayTokens()[Case::Display::TYPE]);
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(displayId);
+    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 1);
+    EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[*displayId]);
 
     // A new display should be connected in its place
 
@@ -1578,13 +1683,12 @@
     // surface(producer)
     sp<BBinder> displayToken = new BBinder();
 
-    DisplayDeviceState info;
-    info.type = Case::Display::TYPE;
-    info.isSecure = static_cast<bool>(Case::Display::SECURE);
+    DisplayDeviceState state;
+    state.isSecure = static_cast<bool>(Case::Display::SECURE);
 
     sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
-    info.surface = surface;
-    mFlinger.mutableCurrentState().displays.add(displayToken, info);
+    state.surface = surface;
+    mFlinger.mutableCurrentState().displays.add(displayToken, state);
 
     // --------------------------------------------------------------------
     // Call Expectations
@@ -1604,7 +1708,6 @@
 
     EXPECT_CALL(*surface, setAsyncMode(true)).Times(1);
 
-    EXPECT_CALL(*mProducer, connect(_, _, _, _)).Times(1);
     EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1);
 
     Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this);
@@ -1646,11 +1749,10 @@
     // surface.
     sp<BBinder> displayToken = new BBinder();
 
-    DisplayDeviceState info;
-    info.type = Case::Display::TYPE;
-    info.isSecure = static_cast<bool>(Case::Display::SECURE);
+    DisplayDeviceState state;
+    state.isSecure = static_cast<bool>(Case::Display::SECURE);
 
-    mFlinger.mutableCurrentState().displays.add(displayToken, info);
+    mFlinger.mutableCurrentState().displays.add(displayToken, state);
 
     // --------------------------------------------------------------------
     // Call Expectations
@@ -1669,7 +1771,7 @@
     // The drawing display state will be set from the current display state.
     ASSERT_TRUE(hasDrawingDisplayState(displayToken));
     const auto& draw = getDrawingDisplayState(displayToken);
-    EXPECT_EQ(Case::Display::TYPE, draw.type);
+    EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
 }
 
 TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) {
@@ -1679,7 +1781,9 @@
     // Preconditions
 
     // A virtual display is set up but is removed from the current state.
-    mFlinger.mutableHwcDisplayData().resize(3);
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(displayId);
+    mFlinger.mutableHwcDisplayData()[*displayId] = {};
     Case::Display::injectHwcDisplay(this);
     auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
     existing.inject();
@@ -1827,11 +1931,16 @@
     // A display is set up
     auto nativeWindow = new mock::NativeWindow();
     auto displaySurface = new mock::DisplaySurface();
-    auto renderSurface = new renderengine::mock::Surface();
+    sp<GraphicBuffer> buf = new GraphicBuffer();
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.setNativeWindow(nativeWindow);
     display.setDisplaySurface(displaySurface);
-    display.setRenderSurface(std::unique_ptr<renderengine::Surface>(renderSurface));
+    // Setup injection expections
+    EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+            .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
+    EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+            .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
+    EXPECT_CALL(*nativeWindow, perform(13)).Times(1);
     display.inject();
 
     // There is a change to the viewport state
@@ -1843,11 +1952,7 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    EXPECT_CALL(*renderSurface, setNativeWindow(nullptr)).Times(1);
     EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1);
-    EXPECT_CALL(*renderSurface, setNativeWindow(nativeWindow)).Times(1);
-    EXPECT_CALL(*renderSurface, getWidth()).WillOnce(Return(newWidth));
-    EXPECT_CALL(*renderSurface, getHeight()).WillOnce(Return(oldHeight));
 
     // --------------------------------------------------------------------
     // Invocation
@@ -1868,11 +1973,16 @@
     // A display is set up
     auto nativeWindow = new mock::NativeWindow();
     auto displaySurface = new mock::DisplaySurface();
-    auto renderSurface = new renderengine::mock::Surface();
+    sp<GraphicBuffer> buf = new GraphicBuffer();
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.setNativeWindow(nativeWindow);
     display.setDisplaySurface(displaySurface);
-    display.setRenderSurface(std::unique_ptr<renderengine::Surface>(renderSurface));
+    // Setup injection expections
+    EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+            .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
+    EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+            .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
+    EXPECT_CALL(*nativeWindow, perform(13)).Times(1);
     display.inject();
 
     // There is a change to the viewport state
@@ -1884,11 +1994,7 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    EXPECT_CALL(*renderSurface, setNativeWindow(nullptr)).Times(1);
     EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1);
-    EXPECT_CALL(*renderSurface, setNativeWindow(nativeWindow)).Times(1);
-    EXPECT_CALL(*renderSurface, getWidth()).WillOnce(Return(oldWidth));
-    EXPECT_CALL(*renderSurface, getHeight()).WillOnce(Return(newHeight));
 
     // --------------------------------------------------------------------
     // Invocation
@@ -2799,9 +2905,10 @@
     // --------------------------------------------------------------------
     // Preconditions
 
-    // We need to resize this so that the HWC thinks the virtual display
-    // is something it created.
-    mFlinger.mutableHwcDisplayData().resize(3);
+    // Insert display data so that the HWC thinks it created the virtual display.
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(displayId);
+    mFlinger.mutableHwcDisplayData()[*displayId] = {};
 
     // A virtual display device is set up
     Case::Display::injectHwcDisplay(this);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 07cabd3..85c835e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -16,21 +16,134 @@
 
 #pragma once
 
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "ColorLayer.h"
+#include "ContainerLayer.h"
 #include "DisplayDevice.h"
 #include "Layer.h"
+#include "NativeWindowSurface.h"
+#include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
+#include "SurfaceFlingerFactory.h"
+#include "SurfaceInterceptor.h"
 
 namespace android {
 
 class EventThread;
 
 namespace renderengine {
+
 class RenderEngine;
-}
+
+} // namespace renderengine
 
 namespace Hwc2 {
+
 class Composer;
-}
+
+} // namespace Hwc2
+
+namespace surfaceflinger::test {
+
+class Factory final : public surfaceflinger::Factory {
+public:
+    ~Factory() = default;
+
+    std::unique_ptr<DispSync> createDispSync(const char*, bool, int64_t) override {
+        // TODO: Use test-fixture controlled factory
+        return nullptr;
+    }
+
+    std::unique_ptr<EventControlThread> createEventControlThread(
+            std::function<void(bool)>) override {
+        // TODO: Use test-fixture controlled factory
+        return nullptr;
+    }
+
+    std::unique_ptr<HWComposer> createHWComposer(const std::string&) override {
+        // TODO: Use test-fixture controlled factory
+        return nullptr;
+    }
+
+    std::unique_ptr<MessageQueue> createMessageQueue() override {
+        // TODO: Use test-fixture controlled factory
+        return std::make_unique<android::impl::MessageQueue>();
+    }
+
+    std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>) override {
+        // TODO: Use test-fixture controlled factory
+        return nullptr;
+    }
+
+    std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
+        // TODO: Use test-fixture controlled factory
+        return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
+    }
+
+    sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
+        // TODO: Use test-fixture controlled factory
+        return new StartPropertySetThread(timestampPropertyValue);
+    }
+
+    sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) override {
+        // TODO: Use test-fixture controlled factory
+        return new DisplayDevice(std::move(creationArgs));
+    }
+
+    sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
+                                          uint32_t layerCount, uint64_t usage,
+                                          std::string requestorName) override {
+        // TODO: Use test-fixture controlled factory
+        return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+    }
+
+    void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+                           sp<IGraphicBufferConsumer>* outConsumer,
+                           bool consumerIsSurfaceFlinger) override {
+        if (!mCreateBufferQueue) return;
+        mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
+    }
+
+    std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
+            const sp<IGraphicBufferProducer>& producer) override {
+        if (!mCreateNativeWindowSurface) return nullptr;
+        return mCreateNativeWindowSurface(producer);
+    }
+
+    sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
+        // TODO: Use test-fixture controlled factory
+        return nullptr;
+    }
+
+    sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs&) override {
+        // TODO: Use test-fixture controlled factory
+        return nullptr;
+    }
+
+    sp<ColorLayer> createColorLayer(const LayerCreationArgs&) override {
+        // TODO: Use test-fixture controlled factory
+        return nullptr;
+    }
+
+    sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override {
+        // TODO: Use test-fixture controlled factory
+        return nullptr;
+    }
+
+    using CreateBufferQueueFunction =
+            std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
+                               sp<IGraphicBufferConsumer>* /* outConsumer */,
+                               bool /* consumerIsSurfaceFlinger */)>;
+    CreateBufferQueueFunction mCreateBufferQueue;
+
+    using CreateNativeWindowSurfaceFunction =
+            std::function<std::unique_ptr<surfaceflinger::NativeWindowSurface>(
+                    const sp<IGraphicBufferProducer>&)>;
+    CreateNativeWindowSurfaceFunction mCreateNativeWindowSurface;
+};
+
+} // namespace surfaceflinger::test
 
 class TestableSurfaceFlinger {
 public:
@@ -45,14 +158,15 @@
         mFlinger->getBE().mHwc.reset(new HWComposer(std::move(composer)));
     }
 
-    using CreateBufferQueueFunction = SurfaceFlinger::CreateBufferQueueFunction;
+    using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
     void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
-        mFlinger->mCreateBufferQueue = f;
+        mFactory.mCreateBufferQueue = f;
     }
 
-    using CreateNativeWindowSurfaceFunction = SurfaceFlinger::CreateNativeWindowSurfaceFunction;
+    using CreateNativeWindowSurfaceFunction =
+            surfaceflinger::test::Factory::CreateNativeWindowSurfaceFunction;
     void setCreateNativeWindowSurface(CreateNativeWindowSurfaceFunction f) {
-        mFlinger->mCreateNativeWindowSurface = f;
+        mFactory.mCreateNativeWindowSurface = f;
     }
 
     using HotplugEvent = SurfaceFlinger::HotplugEvent;
@@ -65,10 +179,6 @@
         layer->getBE().compositionInfo.hwc.sidebandStream = sidebandStream;
     }
 
-    void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
-        layer->getBE().mHwcLayers[DisplayDevice::DISPLAY_PRIMARY].compositionType = type;
-    };
-
     void setLayerPotentialCursor(sp<Layer> layer, bool potentialCursor) {
         layer->mPotentialCursor = potentialCursor;
     }
@@ -87,7 +197,8 @@
 
     auto resetDisplayState() { return mFlinger->resetDisplayState(); }
 
-    auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken, int32_t displayId,
+    auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
+                                       const std::optional<DisplayId>& displayId,
                                        const DisplayDeviceState& state,
                                        const sp<DisplaySurface>& dispSurface,
                                        const sp<IGraphicBufferProducer>& producer) {
@@ -150,7 +261,6 @@
     auto& mutableCurrentState() { return mFlinger->mCurrentState; }
     auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
     auto& mutableDisplays() { return mFlinger->mDisplays; }
-    auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; }
     auto& mutableDrawingState() { return mFlinger->mDrawingState; }
     auto& mutableEventControlThread() { return mFlinger->mEventControlThread; }
     auto& mutableEventQueue() { return mFlinger->mEventQueue; }
@@ -160,6 +270,7 @@
     auto& mutableInterceptor() { return mFlinger->mInterceptor; }
     auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
     auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
+    auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; }
     auto& mutablePrimaryDispSync() { return mFlinger->mPrimaryDispSync; }
     auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; }
     auto& mutableTexturePool() { return mFlinger->mTexturePool; }
@@ -167,8 +278,13 @@
     auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
 
     auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
-    auto& mutableHwcDisplayData() { return mFlinger->getBE().mHwc->mDisplayData; }
-    auto& mutableHwcDisplaySlots() { return mFlinger->getBE().mHwc->mHwcDisplaySlots; }
+    auto& mutableHwcDisplayData() { return mFlinger->getHwComposer().mDisplayData; }
+    auto& mutableHwcPhysicalDisplayIdMap() {
+        return mFlinger->getHwComposer().mPhysicalDisplayIdMap;
+    }
+
+    auto& mutableInternalHwcDisplayId() { return mFlinger->getHwComposer().mInternalHwcDisplayId; }
+    auto& mutableExternalHwcDisplayId() { return mFlinger->getHwComposer().mExternalHwcDisplayId; }
 
     ~TestableSurfaceFlinger() {
         // All these pointer and container clears help ensure that GMock does
@@ -220,8 +336,9 @@
         static constexpr int32_t DEFAULT_DPI = 320;
         static constexpr int32_t DEFAULT_ACTIVE_CONFIG = 0;
 
-        FakeHwcDisplayInjector(DisplayDevice::DisplayType type, HWC2::DisplayType hwcDisplayType)
-              : mType(type), mHwcDisplayType(hwcDisplayType) {}
+        FakeHwcDisplayInjector(DisplayId displayId, HWC2::DisplayType hwcDisplayType,
+                               bool isPrimary)
+              : mDisplayId(displayId), mHwcDisplayType(hwcDisplayType), mIsPrimary(isPrimary) {}
 
         auto& setHwcDisplayId(hwc2_display_t displayId) {
             mHwcDisplayId = displayId;
@@ -290,17 +407,22 @@
             display->mutableConfigs().emplace(mActiveConfig, config.build());
             display->mutableIsConnected() = true;
 
-            ASSERT_TRUE(flinger->mutableHwcDisplayData().size() > static_cast<size_t>(mType));
-            flinger->mutableHwcDisplayData()[mType] = HWComposer::DisplayData();
-            flinger->mutableHwcDisplayData()[mType].hwcDisplay = display.get();
-            flinger->mutableHwcDisplaySlots().emplace(mHwcDisplayId, mType);
+            flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = display.get();
+
+            if (mHwcDisplayType == HWC2::DisplayType::Physical) {
+                flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, mDisplayId);
+                (mIsPrimary ? flinger->mutableInternalHwcDisplayId()
+                            : flinger->mutableExternalHwcDisplayId()) = mHwcDisplayId;
+            }
 
             flinger->mFakeHwcDisplays.push_back(std::move(display));
         }
 
     private:
-        DisplayDevice::DisplayType mType;
-        HWC2::DisplayType mHwcDisplayType;
+        const DisplayId mDisplayId;
+        const HWC2::DisplayType mHwcDisplayType;
+        const bool mIsPrimary;
+
         hwc2_display_t mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
         int32_t mWidth = DEFAULT_WIDTH;
         int32_t mHeight = DEFAULT_HEIGHT;
@@ -314,10 +436,13 @@
 
     class FakeDisplayDeviceInjector {
     public:
-        FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, DisplayDevice::DisplayType type,
-                                  int32_t displayId)
-              : mFlinger(flinger),
-                mCreationArgs(flinger.mFlinger.get(), mDisplayToken, type, displayId) {}
+        FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
+                                  const std::optional<DisplayId>& displayId, bool isVirtual,
+                                  bool isPrimary)
+              : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) {
+            mCreationArgs.isVirtual = isVirtual;
+            mCreationArgs.isPrimary = isPrimary;
+        }
 
         sp<IBinder> token() const { return mDisplayToken; }
 
@@ -349,22 +474,11 @@
             return *this;
         }
 
-        auto& setRenderSurface(std::unique_ptr<renderengine::Surface> renderSurface) {
-            mCreationArgs.renderSurface = std::move(renderSurface);
-            return *this;
-        }
-
         auto& setSecure(bool secure) {
             mCreationArgs.isSecure = secure;
             return *this;
         }
 
-        auto& setDisplaySize(int width, int height) {
-            mCreationArgs.displayWidth = width;
-            mCreationArgs.displayHeight = height;
-            return *this;
-        }
-
         auto& setPowerMode(int mode) {
             mCreationArgs.initialPowerMode = mode;
             return *this;
@@ -384,7 +498,7 @@
 
         sp<DisplayDevice> inject() {
             DisplayDeviceState state;
-            state.type = mCreationArgs.type;
+            state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId;
             state.isSecure = mCreationArgs.isSecure;
 
             sp<DisplayDevice> device = new DisplayDevice(std::move(mCreationArgs));
@@ -392,9 +506,9 @@
             mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
             mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
 
-            if (state.type >= DisplayDevice::DISPLAY_PRIMARY &&
-                state.type < DisplayDevice::DISPLAY_VIRTUAL) {
-                mFlinger.mutableDisplayTokens()[state.type] = mDisplayToken;
+            if (!mCreationArgs.isVirtual) {
+                LOG_ALWAYS_FATAL_IF(!state.displayId);
+                mFlinger.mutablePhysicalDisplayTokens()[*state.displayId] = mDisplayToken;
             }
 
             return device;
@@ -406,7 +520,8 @@
         DisplayDeviceCreationArgs mCreationArgs;
     };
 
-    sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(SurfaceFlinger::SkipInitialization);
+    surfaceflinger::test::Factory mFactory;
+    sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
 
     // We need to keep a reference to these so they are properly destroyed.
     std::vector<std::unique_ptr<HWC2Display>> mFakeHwcDisplays;
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index 495b3f2..34e71cb 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -35,7 +35,6 @@
     MOCK_METHOD1(addResyncSample, bool(nsecs_t));
     MOCK_METHOD0(endResync, void());
     MOCK_METHOD1(setPeriod, void(nsecs_t));
-    MOCK_METHOD1(scalePeriod, void(HWC2::Device::FrequencyScaler));
     MOCK_METHOD0(getPeriod, nsecs_t());
     MOCK_METHOD1(setRefreshSkipCount, void(int));
     MOCK_METHOD3(addEventListener, status_t(const char*, nsecs_t, Callback*));
diff --git a/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h b/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h
index 561fd58..4950a4b 100644
--- a/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h
+++ b/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h
@@ -36,6 +36,7 @@
     MOCK_METHOD1(queueBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
     MOCK_CONST_METHOD2(query, int(int, int*));
     MOCK_METHOD1(perform, int(int));
+    MOCK_METHOD2(perform, int(int, int));
     MOCK_METHOD1(cancelBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
     MOCK_METHOD2(dequeueBuffer, int(struct ANativeWindowBuffer**, int*));
     MOCK_METHOD2(queueBuffer, int(struct ANativeWindowBuffer*, int));
diff --git a/services/thermalservice/Android.bp b/services/thermalservice/Android.bp
deleted file mode 100644
index d754560..0000000
--- a/services/thermalservice/Android.bp
+++ /dev/null
@@ -1,61 +0,0 @@
-subdirs = [
-    "libthermalcallback"
-]
-
-cc_library {
-    name: "libthermalservice",
-
-    srcs: [
-        "aidl/android/os/IThermalEventListener.aidl",
-        "aidl/android/os/IThermalService.aidl",
-        "aidl/android/os/Temperature.cpp",
-    ],
-    aidl: {
-      include_dirs: ["frameworks/native/services/thermalservice/aidl"],
-      export_aidl_headers: true,
-    },
-    export_include_dirs: ["aidl"],
-
-    shared_libs: [
-        "libbinder",
-        "libutils",
-    ],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wunused",
-        "-Wunreachable-code",
-    ],
-}
-
-cc_binary {
-    name: "thermalserviced",
-
-    srcs: [
-        "ThermalService.cpp",
-        "thermalserviced.cpp",
-    ],
-
-    include_dirs: ["frameworks/native"],
-
-    shared_libs: [
-        "libthermalservice",
-        "libbinder",
-        "libutils",
-        "libthermalcallback",
-        "android.hardware.thermal@1.1",
-        "libhidlbase",
-        "libhidltransport",
-        "liblog",
-    ],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wunused",
-        "-Wunreachable-code",
-    ],
-
-    init_rc: ["thermalservice.rc"],
-}
diff --git a/services/thermalservice/ThermalService.cpp b/services/thermalservice/ThermalService.cpp
deleted file mode 100644
index 6e09a83..0000000
--- a/services/thermalservice/ThermalService.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ThermalService.h"
-#include <android/os/IThermalService.h>
-#include <android/os/IThermalEventListener.h>
-#include <android/os/Temperature.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <utils/Errors.h>
-#include <utils/Mutex.h>
-#include <utils/String16.h>
-
-namespace android {
-namespace os {
-
-/**
- * Notify registered listeners of a thermal throttling start/stop event.
- * @param temperature the temperature at which the event was generated
- */
-binder::Status ThermalService::notifyThrottling(
-    const bool isThrottling, const Temperature& temperature) {
-    Mutex::Autolock _l(mListenersLock);
-
-    mThrottled = isThrottling;
-    mThrottleTemperature = temperature;
-
-    for (size_t i = 0; i < mListeners.size(); i++) {
-      mListeners[i]->notifyThrottling(isThrottling, temperature);
-    }
-    return binder::Status::ok();
-}
-
-/**
- * Query whether the system is currently thermal throttling.
- * @return true if currently thermal throttling, else false
- */
-binder::Status ThermalService::isThrottling(bool* _aidl_return) {
-    Mutex::Autolock _l(mListenersLock);
-    *_aidl_return = mThrottled;
-    return binder::Status::ok();
-}
-
-/**
- * Register a new thermal event listener.
- * @param listener the client's IThermalEventListener instance to which
- *                 notifications are to be sent
- */
-binder::Status ThermalService::registerThermalEventListener(
-    const sp<IThermalEventListener>& listener) {
-    {
-        if (listener == NULL)
-            return binder::Status::ok();
-        Mutex::Autolock _l(mListenersLock);
-        // check whether this is a duplicate
-        for (size_t i = 0; i < mListeners.size(); i++) {
-            if (IInterface::asBinder(mListeners[i]) ==
-                IInterface::asBinder(listener)) {
-                return binder::Status::ok();
-            }
-        }
-
-        mListeners.add(listener);
-        IInterface::asBinder(listener)->linkToDeath(this);
-    }
-
-    return binder::Status::ok();
-}
-
-/**
- * Unregister a previously-registered thermal event listener.
- * @param listener the client's IThermalEventListener instance to which
- *                 notifications are to no longer be sent
- */
-binder::Status ThermalService::unregisterThermalEventListener(
-    const sp<IThermalEventListener>& listener) {
-    if (listener == NULL)
-        return binder::Status::ok();
-    Mutex::Autolock _l(mListenersLock);
-    for (size_t i = 0; i < mListeners.size(); i++) {
-        if (IInterface::asBinder(mListeners[i]) ==
-            IInterface::asBinder(listener)) {
-            IInterface::asBinder(mListeners[i])->unlinkToDeath(this);
-            mListeners.removeAt(i);
-            break;
-        }
-    }
-
-    return binder::Status::ok();
-}
-
-void ThermalService::binderDied(const wp<IBinder>& who) {
-    Mutex::Autolock _l(mListenersLock);
-
-    for (size_t i = 0; i < mListeners.size(); i++) {
-        if (IInterface::asBinder(mListeners[i]) == who) {
-            mListeners.removeAt(i);
-            break;
-        }
-    }
-}
-
-/**
- * Publish the supplied ThermalService to servicemanager.
- */
-void ThermalService::publish(
-    const sp<ThermalService>& service) {
-    defaultServiceManager()->addService(String16("thermalservice"),
-                                        service);
-}
-
-}  // namespace os
-}  // namespace android
diff --git a/services/thermalservice/ThermalService.h b/services/thermalservice/ThermalService.h
deleted file mode 100644
index 17dfcbc..0000000
--- a/services/thermalservice/ThermalService.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_THERMALSERVICE_THERMALSERVICE_H
-#define ANDROID_THERMALSERVICE_THERMALSERVICE_H
-
-#include <android/os/BnThermalService.h>
-#include <android/os/IThermalEventListener.h>
-#include <android/os/Temperature.h>
-#include <utils/Mutex.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-namespace android {
-namespace os {
-
-class ThermalService : public BnThermalService,
-                       public IBinder::DeathRecipient {
-public:
-  ThermalService() : mThrottled(false) {};
-    void publish(const sp<ThermalService>& service);
-    binder::Status notifyThrottling(
-        const bool isThrottling, const Temperature& temperature);
-
-private:
-    Mutex mListenersLock;
-    Vector<sp<IThermalEventListener> > mListeners;
-    bool mThrottled;
-    Temperature mThrottleTemperature;
-
-    binder::Status registerThermalEventListener(
-        const sp<IThermalEventListener>& listener);
-    binder::Status unregisterThermalEventListener(
-        const sp<IThermalEventListener>& listener);
-    binder::Status isThrottling(bool* _aidl_return);
-    void binderDied(const wp<IBinder>& who);
-};
-
-};  // namespace os
-};  // namespace android
-
-#endif // ANDROID_THERMALSERVICE_THERMALSERVICE_H
diff --git a/services/thermalservice/aidl/android/os/IThermalEventListener.aidl b/services/thermalservice/aidl/android/os/IThermalEventListener.aidl
deleted file mode 100644
index 050325e..0000000
--- a/services/thermalservice/aidl/android/os/IThermalEventListener.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.os.Temperature;
-
-/**
-  * Listener for thermal events.
-  * {@hide}
-  */
-oneway interface IThermalEventListener {
-    /**
-     * Called when a thermal throttling start/stop event is received.
-     * @param temperature the temperature at which the event was generated.
-     */
-    void notifyThrottling(
-        in boolean isThrottling, in Temperature temperature);
-}
diff --git a/services/thermalservice/aidl/android/os/IThermalService.aidl b/services/thermalservice/aidl/android/os/IThermalService.aidl
deleted file mode 100644
index e699202..0000000
--- a/services/thermalservice/aidl/android/os/IThermalService.aidl
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.os.IThermalEventListener;
-import android.os.Temperature;
-
-/** {@hide} */
-interface IThermalService {
-    /**
-      * Register a listener for thermal events.
-      * @param listener the IThermalEventListener to be notified.
-      * {@hide}
-      */
-    void registerThermalEventListener(in IThermalEventListener listener);
-    /**
-      * Unregister a previously-registered listener for thermal events.
-      * @param listener the IThermalEventListener to no longer be notified.
-      * {@hide}
-      */
-    void unregisterThermalEventListener(in IThermalEventListener listener);
-    /**
-      * Send a thermal throttling start/stop notification to all listeners.
-      * @param temperature the temperature at which the event was generated.
-      * {@hide}
-      */
-    oneway void notifyThrottling(
-        in boolean isThrottling, in Temperature temperature);
-    /**
-      * Return whether system performance is currently thermal throttling.
-      * {@hide}
-      */
-    boolean isThrottling();
-}
diff --git a/services/thermalservice/aidl/android/os/Temperature.aidl b/services/thermalservice/aidl/android/os/Temperature.aidl
deleted file mode 100644
index 0293c39..0000000
--- a/services/thermalservice/aidl/android/os/Temperature.aidl
+++ /dev/null
@@ -1,5 +0,0 @@
-package android.os;
-
-/* Encodes a temperature used by ThermalService. */
-
-parcelable Temperature cpp_header "android/os/Temperature.h";
diff --git a/services/thermalservice/aidl/android/os/Temperature.cpp b/services/thermalservice/aidl/android/os/Temperature.cpp
deleted file mode 100644
index df207b7..0000000
--- a/services/thermalservice/aidl/android/os/Temperature.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "android/os/Temperature.h"
-
-#include <math.h>
-#include <stdint.h>
-#include <binder/Parcel.h>
-#include <hardware/thermal.h>
-#include <sys/types.h>
-#include <utils/Errors.h>
-
-namespace android {
-namespace os {
-
-Temperature::Temperature() : value_(NAN), type_(DEVICE_TEMPERATURE_UNKNOWN) {}
-
-Temperature::Temperature(const float value, const int type) :
-    value_(value), type_(type)  {}
-
-Temperature::~Temperature() {}
-
-/*
- * Parcel read/write code must be kept in sync with
- * frameworks/base/core/java/android/os/Temperature.java
- */
-
-status_t Temperature::readFromParcel(const Parcel* p) {
-    value_ = p->readFloat();
-    type_ = p->readInt32();
-    return OK;
-}
-
-status_t Temperature::writeToParcel(Parcel* p) const {
-    p->writeFloat(value_);
-    p->writeInt32(type_);
-    return OK;
-}
-
-}  // namespace os
-}  // namespace android
diff --git a/services/thermalservice/aidl/android/os/Temperature.h b/services/thermalservice/aidl/android/os/Temperature.h
deleted file mode 100644
index bbc5607..0000000
--- a/services/thermalservice/aidl/android/os/Temperature.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
-#define ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
-
-#include <binder/Parcelable.h>
-
-namespace android {
-namespace os {
-
-class Temperature : public Parcelable {
- public:
-
-  Temperature();
-  Temperature(const float value, const int type);
-  ~Temperature() override;
-
-  float getValue() const {return value_;};
-  float getType() const {return type_;};
-
-  status_t writeToParcel(Parcel* parcel) const override;
-  status_t readFromParcel(const Parcel* parcel) override;
-
- private:
-  // The value of the temperature as a float, or NAN if unknown.
-  float value_;
-  // The type of the temperature, an enum temperature_type from
-  // hardware/thermal.h
-  int type_;
-};
-
-}  // namespace os
-}  // namespace android
-
-#endif   // ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
diff --git a/services/thermalservice/libthermalcallback/Android.bp b/services/thermalservice/libthermalcallback/Android.bp
deleted file mode 100644
index e98506e..0000000
--- a/services/thermalservice/libthermalcallback/Android.bp
+++ /dev/null
@@ -1,19 +0,0 @@
-cc_library_shared {
-    name: "libthermalcallback",
-    srcs: [
-        "ThermalCallback.cpp",
-    ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-    include_dirs: ["frameworks/native"],
-    shared_libs: [
-        "android.hardware.thermal@1.1",
-        "libhidlbase",
-        "libhidltransport",
-        "liblog",
-        "libthermalservice",
-        "libutils",
-    ],
-}
diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.cpp b/services/thermalservice/libthermalcallback/ThermalCallback.cpp
deleted file mode 100644
index 5e094fa..0000000
--- a/services/thermalservice/libthermalcallback/ThermalCallback.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-#define LOG_TAG "android.hardware.thermal.thermalcallback@1.1-impl"
-#include <log/log.h>
-
-#include "ThermalCallback.h"
-#include "services/thermalservice/ThermalService.h"
-#include <math.h>
-#include <android/os/Temperature.h>
-#include <hardware/thermal.h>
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V1_1 {
-namespace implementation {
-
-using ::android::os::ThermalService;
-using ::android::hardware::thermal::V1_0::TemperatureType;
-
-// Register a binder ThermalService object for sending events
-void ThermalCallback::registerThermalService(sp<ThermalService> thermalService)
-{
-    mThermalService = thermalService;
-}
-
-// Methods from IThermalCallback::V1_1 follow.
-Return<void> ThermalCallback::notifyThrottling(
-      bool isThrottling,
-      const android::hardware::thermal::V1_0::Temperature& temperature) {
-
-    // Convert HIDL IThermal Temperature to binder IThermalService Temperature.
-    if (mThermalService != nullptr) {
-        float value = NAN;
-        int type = DEVICE_TEMPERATURE_UNKNOWN;
-
-        switch(temperature.type) {
-          case TemperatureType::CPU:
-            type = DEVICE_TEMPERATURE_CPU;
-            break;
-          case TemperatureType::GPU:
-            type = DEVICE_TEMPERATURE_GPU;
-            break;
-          case TemperatureType::BATTERY:
-            type = DEVICE_TEMPERATURE_BATTERY;
-            break;
-          case TemperatureType::SKIN:
-            type = DEVICE_TEMPERATURE_SKIN;
-            break;
-          case TemperatureType::UNKNOWN:
-          default:
-            type = DEVICE_TEMPERATURE_UNKNOWN;
-            break;
-        }
-
-        value = temperature.currentValue == UNKNOWN_TEMPERATURE ? NAN :
-            temperature.currentValue;
-
-        android::os::Temperature thermal_svc_temp(value, type);
-        mThermalService->notifyThrottling(isThrottling, thermal_svc_temp);
-    } else {
-        ALOGE("IThermalService binder service not created, drop throttling event");
-    }
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace thermal
-}  // namespace hardware
-}  // namespace android
diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.h b/services/thermalservice/libthermalcallback/ThermalCallback.h
deleted file mode 100644
index 3d72c68..0000000
--- a/services/thermalservice/libthermalcallback/ThermalCallback.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
-#define ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
-
-#include <android/hardware/thermal/1.1/IThermalCallback.h>
-#include <android/hardware/thermal/1.0/types.h>
-#include <android/os/Temperature.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include "services/thermalservice/ThermalService.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V1_1 {
-namespace implementation {
-
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::os::ThermalService;
-
-class ThermalCallback : public IThermalCallback {
- public:
-    // Register a binder ThermalService object for sending events
-    void registerThermalService(sp<ThermalService> thermalService);
-
-    // Methods from IThermalCallback::V1_1 follow.
-    Return<void> notifyThrottling(
-        bool isThrottling,
-        const android::hardware::thermal::V1_0::Temperature& temperature)
-        override;
-
- private:
-    // Our registered binder ThermalService object to use for sending events
-    sp<android::os::ThermalService> mThermalService;
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace thermal
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
diff --git a/services/thermalservice/thermalservice.rc b/services/thermalservice/thermalservice.rc
deleted file mode 100644
index 94c2c78..0000000
--- a/services/thermalservice/thermalservice.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service thermalservice /system/bin/thermalserviced
-    class core
-    user system
-    group system
diff --git a/services/thermalservice/thermalserviced.cpp b/services/thermalservice/thermalserviced.cpp
deleted file mode 100644
index 8e27266..0000000
--- a/services/thermalservice/thermalserviced.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "thermalserviced"
-#include <log/log.h>
-
-#include "thermalserviced.h"
-#include "ThermalService.h"
-#include "libthermalcallback/ThermalCallback.h"
-
-#include <android/hardware/thermal/1.1/IThermal.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <hidl/HidlTransportSupport.h>
-
-using namespace android;
-using ::android::hardware::thermal::V1_1::IThermal;
-using ::android::hardware::thermal::V1_0::Temperature;
-using ::android::hardware::thermal::V1_1::IThermalCallback;
-using ::android::hardware::thermal::V1_1::implementation::ThermalCallback;
-using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::hidl_death_recipient;
-using ::android::hidl::base::V1_0::IBase;
-using ::android::os::ThermalService;
-
-template<typename T>
-using Return = hardware::Return<T>;
-
-namespace {
-
-// Our thermalserviced main object
-ThermalServiceDaemon* gThermalServiceDaemon;
-
-// Thermal HAL client
-sp<IThermal> gThermalHal = nullptr;
-
-// Binder death notifier informing of Thermal HAL death.
-struct ThermalServiceDeathRecipient : hidl_death_recipient {
-    virtual void serviceDied(
-        uint64_t cookie __unused, const wp<IBase>& who __unused) {
-        gThermalHal = nullptr;
-        ALOGE("IThermal HAL died");
-        gThermalServiceDaemon->getThermalHal();
-    }
-};
-
-sp<ThermalServiceDeathRecipient> gThermalHalDied = nullptr;
-
-}  // anonymous namespace
-
-void ThermalServiceDaemon::thermalServiceStartup() {
-    // Binder IThermalService startup
-    mThermalService = new android::os::ThermalService;
-    mThermalService->publish(mThermalService);
-    // Register IThermalService object with IThermalCallback
-    if (mThermalCallback != nullptr)
-        mThermalCallback->registerThermalService(mThermalService);
-    IPCThreadState::self()->joinThreadPool();
-}
-
-// Lookup Thermal HAL, register death notifier, register our
-// ThermalCallback with the Thermal HAL.
-void ThermalServiceDaemon::getThermalHal() {
-    gThermalHal = IThermal::getService();
-    if (gThermalHal == nullptr) {
-        ALOGW("Unable to get Thermal HAL V1.1, vendor thermal event notification not available");
-        return;
-    }
-
-    // Binder death notifier for Thermal HAL
-    if (gThermalHalDied == nullptr)
-        gThermalHalDied = new ThermalServiceDeathRecipient();
-
-    if (gThermalHalDied != nullptr)
-        gThermalHal->linkToDeath(gThermalHalDied, 0x451F /* cookie */);
-
-    if (mThermalCallback != nullptr) {
-        Return<void> ret = gThermalHal->registerThermalCallback(
-            mThermalCallback);
-        if (!ret.isOk())
-            ALOGE("registerThermalCallback failed, status: %s",
-                  ret.description().c_str());
-    }
-}
-
-void ThermalServiceDaemon::thermalCallbackStartup() {
-    // HIDL IThermalCallback startup
-    // Need at least 2 threads in thread pool since we wait for dead HAL
-    // to come back on the binder death notification thread and we need
-    // another thread for the incoming service now available call.
-    configureRpcThreadpool(2, false /* callerWillJoin */);
-    mThermalCallback = new ThermalCallback();
-    // Lookup Thermal HAL and register our ThermalCallback.
-    getThermalHal();
-}
-
-int main(int /*argc*/, char** /*argv*/) {
-    gThermalServiceDaemon = new ThermalServiceDaemon();
-    gThermalServiceDaemon->thermalCallbackStartup();
-    gThermalServiceDaemon->thermalServiceStartup();
-    /* NOTREACHED */
-}
diff --git a/services/thermalservice/thermalserviced.h b/services/thermalservice/thermalserviced.h
deleted file mode 100644
index 309e2fe..0000000
--- a/services/thermalservice/thermalserviced.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_THERMALSERVICE_THERMALSERVICED_H
-#define ANDROID_THERMALSERVICE_THERMALSERVICED_H
-
-#include "ThermalService.h"
-#include "libthermalcallback/ThermalCallback.h"
-
-using namespace android;
-using ::android::hardware::thermal::V1_0::Temperature;
-using ::android::hardware::thermal::V1_1::implementation::ThermalCallback;
-using ::android::os::ThermalService;
-
-class ThermalServiceDaemon {
- public:
-    void thermalServiceStartup();
-    void thermalCallbackStartup();
-    void getThermalHal();
-    ThermalServiceDaemon() {};
-
- private:
-    sp<ThermalService> mThermalService;
-    sp<ThermalCallback> mThermalCallback;
-};
-
-#endif  // ANDROID_THERMALSERVICE_THERMALSERVICED_H
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index c35ddd4..b5e6bb4 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -15,6 +15,7 @@
 sharedLibraries = [
     "libbase",
     "libbinder",
+    "libbufferhubservice",
     "libcutils",
     "libgtest_prod",
     "libgui",
@@ -29,9 +30,9 @@
     name: "libbufferhubd",
     srcs: [
         "buffer_channel.cpp",
+        "buffer_client.cpp",
         "buffer_hub.cpp",
         "buffer_hub_binder.cpp",
-        "buffer_node.cpp",
         "consumer_channel.cpp",
         "consumer_queue_channel.cpp",
         "IBufferHub.cpp",
@@ -44,7 +45,10 @@
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
     ],
     export_include_dirs: ["include"],
-    header_libs: ["libdvr_headers"],
+    header_libs: [
+        "libdvr_headers",
+        "libnativewindow_headers",
+    ],
     shared_libs: sharedLibraries,
     static_libs: [
         "libbufferhub",
diff --git a/services/vr/bufferhubd/IBufferHub.cpp b/services/vr/bufferhubd/IBufferHub.cpp
index 2f39e41..022a9cc 100644
--- a/services/vr/bufferhubd/IBufferHub.cpp
+++ b/services/vr/bufferhubd/IBufferHub.cpp
@@ -13,6 +13,8 @@
                                  uint32_t layer_count, uint32_t format,
                                  uint64_t usage,
                                  uint64_t user_metadata_size) override;
+
+  status_t importBuffer(uint64_t token, sp<IBufferClient>* outClient) override;
 };
 
 IMPLEMENT_META_INTERFACE(BufferHub, "android.dvr.IBufferHub");
@@ -20,6 +22,7 @@
 // Transaction code
 enum {
   CREATE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+  IMPORT_BUFFER,
 };
 
 sp<IBufferClient> BpBufferHub::createBuffer(uint32_t width, uint32_t height,
@@ -50,6 +53,27 @@
   }
 }
 
+status_t BpBufferHub::importBuffer(uint64_t token,
+                                   sp<IBufferClient>* outClient) {
+  Parcel data, reply;
+  status_t ret = NO_ERROR;
+  ret |= data.writeInterfaceToken(IBufferHub::getInterfaceDescriptor());
+  ret |= data.writeUint64(token);
+  if (ret != NO_ERROR) {
+    ALOGE("BpBufferHub::importBuffer: failed to write into parcel");
+    return ret;
+  }
+
+  ret = remote()->transact(IMPORT_BUFFER, data, &reply);
+  if (ret == NO_ERROR) {
+    *outClient = interface_cast<IBufferClient>(reply.readStrongBinder());
+    return NO_ERROR;
+  } else {
+    ALOGE("BpBufferHub::importBuffer: failed to transact; errno=%d", ret);
+    return ret;
+  }
+}
+
 status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags) {
   switch (code) {
@@ -64,7 +88,18 @@
       sp<IBufferClient> ret = createBuffer(width, height, layer_count, format,
                                            usage, user_metadata_size);
       return reply->writeStrongBinder(IInterface::asBinder(ret));
-    } break;
+    }
+    case IMPORT_BUFFER: {
+      CHECK_INTERFACE(IBufferHub, data, reply);
+      uint64_t token = data.readUint64();
+      sp<IBufferClient> client;
+      status_t ret = importBuffer(token, &client);
+      if (ret == NO_ERROR) {
+        return reply->writeStrongBinder(IInterface::asBinder(client));
+      } else {
+        return ret;
+      }
+    }
     default:
       // Should not reach except binder defined transactions such as dumpsys
       return BBinder::onTransact(code, data, reply, flags);
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
index ee85746..589b31a 100644
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -13,22 +13,17 @@
 namespace dvr {
 
 BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
-                             int channel_id, IonBuffer buffer,
-                             size_t user_metadata_size)
-    : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
-      buffer_node_(
-          std::make_shared<BufferNode>(std::move(buffer), user_metadata_size)) {
-  buffer_state_bit_ = buffer_node_->AddNewActiveClientsBitToMask();
-}
-
-BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
                              uint32_t width, uint32_t height,
                              uint32_t layer_count, uint32_t format,
                              uint64_t usage, size_t user_metadata_size)
-    : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
-      buffer_node_(std::make_shared<BufferNode>(
-          width, height, layer_count, format, usage, user_metadata_size)) {
-  buffer_state_bit_ = buffer_node_->AddNewActiveClientsBitToMask();
+    : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType) {
+  buffer_node_ = std::make_shared<BufferNode>(
+      width, height, layer_count, format, usage, user_metadata_size);
+  if (!buffer_node_->IsValid()) {
+    ALOGE("BufferChannel::BufferChannel: Failed to create BufferNode.");
+    return;
+  }
+  client_state_mask_ = buffer_node_->AddNewActiveClientsBitToMask();
 }
 
 BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
@@ -36,8 +31,8 @@
                              std::shared_ptr<BufferNode> buffer_node)
     : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
       buffer_node_(buffer_node) {
-  buffer_state_bit_ = buffer_node_->AddNewActiveClientsBitToMask();
-  if (buffer_state_bit_ == 0ULL) {
+  client_state_mask_ = buffer_node_->AddNewActiveClientsBitToMask();
+  if (client_state_mask_ == 0ULL) {
     ALOGE("BufferChannel::BufferChannel: %s", strerror(errno));
     buffer_node_ = nullptr;
   }
@@ -46,17 +41,17 @@
 BufferChannel::~BufferChannel() {
   ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
            channel_id(), buffer_id());
-  if (buffer_state_bit_ != 0ULL) {
-    buffer_node_->RemoveClientsBitFromMask(buffer_state_bit_);
+  if (client_state_mask_ != 0ULL) {
+    buffer_node_->RemoveClientsBitFromMask(client_state_mask_);
   }
   Hangup();
 }
 
 BufferHubChannel::BufferInfo BufferChannel::GetBufferInfo() const {
   return BufferInfo(
-      buffer_id(), /*consumer_count=*/0, buffer_node_->buffer().width(),
-      buffer_node_->buffer().height(), buffer_node_->buffer().layer_count(),
-      buffer_node_->buffer().format(), buffer_node_->buffer().usage(),
+      buffer_id(), /*consumer_count=*/0, buffer_node_->buffer_desc().width,
+      buffer_node_->buffer_desc().height, buffer_node_->buffer_desc().layers,
+      buffer_node_->buffer_desc().format, buffer_node_->buffer_desc().usage,
       /*pending_count=*/0, /*state=*/0, /*signaled_mask=*/0,
       /*index=*/0);
 }
@@ -90,17 +85,17 @@
 
   // TODO(b/112057680) Move away from the GraphicBuffer-based IonBuffer.
   return BufferTraits<BorrowedHandle>{
-      /*buffer_handle=*/buffer_node_->buffer().handle(),
+      /*buffer_handle=*/buffer_node_->buffer_handle(),
       /*metadata_handle=*/buffer_node_->metadata().ashmem_handle().Borrow(),
       /*id=*/buffer_id(),
-      /*buffer_state_bit=*/buffer_state_bit_,
+      /*client_state_mask=*/client_state_mask_,
       /*metadata_size=*/buffer_node_->metadata().metadata_size(),
-      /*width=*/buffer_node_->buffer().width(),
-      /*height=*/buffer_node_->buffer().height(),
-      /*layer_count=*/buffer_node_->buffer().layer_count(),
-      /*format=*/buffer_node_->buffer().format(),
-      /*usage=*/buffer_node_->buffer().usage(),
-      /*stride=*/buffer_node_->buffer().stride(),
+      /*width=*/buffer_node_->buffer_desc().width,
+      /*height=*/buffer_node_->buffer_desc().height,
+      /*layer_count=*/buffer_node_->buffer_desc().layers,
+      /*format=*/buffer_node_->buffer_desc().format,
+      /*usage=*/buffer_node_->buffer_desc().usage,
+      /*stride=*/buffer_node_->buffer_desc().stride,
       /*acquire_fence_fd=*/BorrowedHandle{},
       /*released_fence_fd=*/BorrowedHandle{}};
 }
diff --git a/services/vr/bufferhubd/buffer_client.cpp b/services/vr/bufferhubd/buffer_client.cpp
new file mode 100644
index 0000000..f14faf7
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_client.cpp
@@ -0,0 +1,18 @@
+#include <private/dvr/buffer_client.h>
+#include <private/dvr/buffer_hub_binder.h>
+
+namespace android {
+namespace dvr {
+
+status_t BufferClient::duplicate(uint64_t* outToken) {
+  if (!buffer_node_) {
+    // Should never happen
+    ALOGE("BufferClient::duplicate: node is missing.");
+    return UNEXPECTED_NULL;
+  }
+  return service_->registerToken(std::weak_ptr<BufferNode>(buffer_node_),
+                                 outToken);
+}
+
+}  // namespace dvr
+}  // namespace android
\ No newline at end of file
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 6421a0b..b73c47d 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -256,15 +256,6 @@
           *this, &BufferHubService::OnCreateProducerQueue, message);
       return {};
 
-    case BufferHubRPC::ProducerBufferDetach::Opcode:
-      // In addition to the message handler in the ProducerChannel's
-      // HandleMessage method, we also need to invalid the producer channel (and
-      // all associated consumer channels). Note that this has to be done after
-      // HandleMessage returns to make sure the IPC request has went back to the
-      // client first.
-      SetChannel(channel->channel_id(), nullptr);
-      return {};
-
     default:
       return DefaultHandleMessage(message);
   }
diff --git a/services/vr/bufferhubd/buffer_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp
index 7da1532..afd34aa 100644
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ b/services/vr/bufferhubd/buffer_hub_binder.cpp
@@ -46,8 +46,14 @@
             "Input arguments are ignored.\n");
   }
 
-  // TODO(b/116526156): output real data in this class once we have it
+  fprintf(out, "Binder service:\n");
+  // Active buffers
+  fprintf(out, "Active BufferClients: %zu\n", client_list_.size());
+  // TODO(b/117790952): print buffer information after BufferNode has it
+  // TODO(b/116526156): print more information once we have them
+
   if (pdx_service_) {
+    fprintf(out, "\nPDX service:\n");
     // BufferHubService::Dumpstate(size_t) is not actually using the param
     // So just using 0 as the length
     fprintf(out, "%s", pdx_service_->DumpState(0).c_str());
@@ -59,23 +65,14 @@
   return NO_ERROR;
 }
 
-sp<IBufferHub> BufferHubBinderService::getServiceProxy() {
-  sp<IServiceManager> sm = defaultServiceManager();
-  sp<IBinder> service = sm->checkService(String16(getServiceName()));
+status_t BufferHubBinderService::registerToken(
+    const std::weak_ptr<BufferNode> node, uint64_t* outToken) {
+  do {
+    *outToken = token_engine_();
+  } while (token_map_.find(*outToken) != token_map_.end());
 
-  if (service == nullptr) {
-    ALOGE("getServiceProxy(): %s binder service not found!", getServiceName());
-    return nullptr;
-  }
-
-  sp<IBufferHub> ret = interface_cast<IBufferHub>(service);
-  if (ret == nullptr) {
-    ALOGE("getServiceProxy(): %s binder service type casting error!",
-          getServiceName());
-    return nullptr;
-  }
-
-  return ret;
+  token_map_.emplace(*outToken, node);
+  return NO_ERROR;
 }
 
 sp<IBufferClient> BufferHubBinderService::createBuffer(
@@ -84,12 +81,49 @@
   std::shared_ptr<BufferNode> node = std::make_shared<BufferNode>(
       width, height, layer_count, format, usage, user_metadata_size);
 
-  sp<BufferClient> client = new BufferClient(node);
+  sp<BufferClient> client = new BufferClient(node, this);
   // Add it to list for bookkeeping and dumpsys.
   client_list_.push_back(client);
 
   return client;
 }
 
+status_t BufferHubBinderService::importBuffer(uint64_t token,
+                                              sp<IBufferClient>* outClient) {
+  auto iter = token_map_.find(token);
+
+  if (iter == token_map_.end()) {  // Not found
+    ALOGE("BufferHubBinderService::importBuffer: token %" PRIu64
+          "does not exist.",
+          token);
+    return PERMISSION_DENIED;
+  }
+
+  if (iter->second.expired()) {  // Gone
+    ALOGW(
+        "BufferHubBinderService::importBuffer: the original node of token "
+        "%" PRIu64 "has gone.",
+        token);
+    token_map_.erase(iter);
+    return DEAD_OBJECT;
+  }
+
+  // Promote the weak_ptr
+  std::shared_ptr<BufferNode> node(iter->second);
+  if (!node) {
+    ALOGE("BufferHubBinderService::importBuffer: promote weak_ptr failed.");
+    token_map_.erase(iter);
+    return DEAD_OBJECT;
+  }
+
+  sp<BufferClient> client = new BufferClient(node, this);
+  *outClient = client;
+
+  token_map_.erase(iter);
+  client_list_.push_back(client);
+
+  return NO_ERROR;
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
deleted file mode 100644
index bedec6f..0000000
--- a/services/vr/bufferhubd/buffer_node.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#include <errno.h>
-#include <private/dvr/buffer_hub_defs.h>
-#include <private/dvr/buffer_node.h>
-
-namespace android {
-namespace dvr {
-
-void BufferNode::InitializeMetadata() {
-  // Using placement new here to reuse shared memory instead of new allocation
-  // Initialize the atomic variables to zero.
-  BufferHubDefs::MetadataHeader* metadata_header = metadata_.metadata_header();
-  buffer_state_ = new (&metadata_header->buffer_state) std::atomic<uint64_t>(0);
-  fence_state_ = new (&metadata_header->fence_state) std::atomic<uint64_t>(0);
-  active_clients_bit_mask_ =
-      new (&metadata_header->active_clients_bit_mask) std::atomic<uint64_t>(0);
-}
-
-BufferNode::BufferNode(IonBuffer buffer, size_t user_metadata_size)
-    : buffer_(std::move(buffer)) {
-  metadata_ = BufferHubMetadata::Create(user_metadata_size);
-  InitializeMetadata();
-}
-
-// Allocates a new BufferNode.
-BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
-                       uint32_t format, uint64_t usage,
-                       size_t user_metadata_size) {
-  if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
-    ALOGE(
-        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
-        "buffer: %s",
-        strerror(-ret));
-    return;
-  }
-
-  metadata_ = BufferHubMetadata::Create(user_metadata_size);
-  InitializeMetadata();
-}
-
-uint64_t BufferNode::GetActiveClientsBitMask() const {
-  return active_clients_bit_mask_->load(std::memory_order_acquire);
-}
-
-uint64_t BufferNode::AddNewActiveClientsBitToMask() {
-  uint64_t current_active_clients_bit_mask = GetActiveClientsBitMask();
-  uint64_t buffer_state_bit = 0ULL;
-  uint64_t updated_active_clients_bit_mask = 0ULL;
-  do {
-    buffer_state_bit =
-        BufferHubDefs::FindNextClearedBit(current_active_clients_bit_mask);
-    if (buffer_state_bit == 0ULL) {
-      ALOGE(
-          "BufferNode::AddNewActiveClientsBitToMask: reached the maximum "
-          "mumber of channels per buffer node: 32.");
-      errno = E2BIG;
-      return 0ULL;
-    }
-    updated_active_clients_bit_mask =
-        current_active_clients_bit_mask | buffer_state_bit;
-  } while (!(active_clients_bit_mask_->compare_exchange_weak(
-      current_active_clients_bit_mask, updated_active_clients_bit_mask,
-      std::memory_order_acq_rel, std::memory_order_acquire)));
-  return buffer_state_bit;
-}
-
-void BufferNode::RemoveClientsBitFromMask(const uint64_t& value) {
-  active_clients_bit_mask_->fetch_and(~value);
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp
index 4ff7adf..98ef917 100644
--- a/services/vr/bufferhubd/consumer_channel.cpp
+++ b/services/vr/bufferhubd/consumer_channel.cpp
@@ -17,10 +17,10 @@
 namespace dvr {
 
 ConsumerChannel::ConsumerChannel(BufferHubService* service, int buffer_id,
-                                 int channel_id, uint64_t consumer_state_bit,
+                                 int channel_id, uint64_t client_state_mask,
                                  const std::shared_ptr<Channel> producer)
     : BufferHubChannel(service, buffer_id, channel_id, kConsumerType),
-      consumer_state_bit_(consumer_state_bit),
+      client_state_mask_(client_state_mask),
       producer_(producer) {
   GetProducer()->AddConsumer(this);
 }
@@ -41,7 +41,7 @@
     // If producer has not hung up, copy most buffer info from the producer.
     info = producer->GetBufferInfo();
   } else {
-    info.signaled_mask = consumer_state_bit();
+    info.signaled_mask = client_state_mask();
   }
   info.id = buffer_id();
   return info;
@@ -100,7 +100,7 @@
   ATRACE_NAME("ConsumerChannel::OnGetBuffer");
   ALOGD_IF(TRACE, "ConsumerChannel::OnGetBuffer: buffer=%d", buffer_id());
   if (auto producer = GetProducer()) {
-    return {producer->GetBuffer(consumer_state_bit_)};
+    return {producer->GetBuffer(client_state_mask_)};
   } else {
     return ErrorStatus(EPIPE);
   }
diff --git a/services/vr/bufferhubd/consumer_queue_channel.cpp b/services/vr/bufferhubd/consumer_queue_channel.cpp
index 74b549d..5d7d4e9 100644
--- a/services/vr/bufferhubd/consumer_queue_channel.cpp
+++ b/services/vr/bufferhubd/consumer_queue_channel.cpp
@@ -80,27 +80,35 @@
 }
 
 void ConsumerQueueChannel::RegisterNewBuffer(
-    const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot) {
-  ALOGD_IF(TRACE,
-           "ConsumerQueueChannel::RegisterNewBuffer: queue_id=%d buffer_id=%d "
-           "slot=%zu silent=%d",
-           buffer_id(), producer_channel->buffer_id(), slot, silent_);
+    const std::shared_ptr<ProducerChannel>& producer_channel,
+    size_t producer_slot) {
+  ALOGD_IF(TRACE, "%s: queue_id=%d buffer_id=%d slot=%zu silent=%d",
+           __FUNCTION__, buffer_id(), producer_channel->buffer_id(),
+           producer_slot, silent_);
   // Only register buffers if the queue is not silent.
-  if (!silent_) {
-    pending_buffer_slots_.emplace(producer_channel, slot);
-
-    // Signal the client that there is new buffer available.
-    SignalAvailable();
+  if (silent_) {
+    return;
   }
+
+  auto status = producer_channel->CreateConsumerStateMask();
+  if (!status.ok()) {
+    ALOGE("%s: Failed to create consumer state mask: %s", __FUNCTION__,
+          status.GetErrorMessage().c_str());
+    return;
+  }
+  uint64_t consumer_state_mask = status.get();
+
+  pending_buffer_slots_.emplace(producer_channel, producer_slot,
+                                consumer_state_mask);
+  // Signal the client that there is new buffer available.
+  SignalAvailable();
 }
 
 Status<std::vector<std::pair<RemoteChannelHandle, size_t>>>
 ConsumerQueueChannel::OnConsumerQueueImportBuffers(Message& message) {
   std::vector<std::pair<RemoteChannelHandle, size_t>> buffer_handles;
-  ATRACE_NAME("ConsumerQueueChannel::OnConsumerQueueImportBuffers");
-  ALOGD_IF(TRACE,
-           "ConsumerQueueChannel::OnConsumerQueueImportBuffers: "
-           "pending_buffer_slots=%zu",
+  ATRACE_NAME(__FUNCTION__);
+  ALOGD_IF(TRACE, "%s: pending_buffer_slots=%zu", __FUNCTION__,
            pending_buffer_slots_.size());
 
   // Indicate this is a silent queue that will not import buffers.
@@ -108,30 +116,30 @@
     return ErrorStatus(EBADR);
 
   while (!pending_buffer_slots_.empty()) {
-    auto producer_channel = pending_buffer_slots_.front().first.lock();
-    size_t producer_slot = pending_buffer_slots_.front().second;
+    auto producer_channel =
+        pending_buffer_slots_.front().producer_channel.lock();
+    size_t producer_slot = pending_buffer_slots_.front().producer_slot;
+    uint64_t consumer_state_mask =
+        pending_buffer_slots_.front().consumer_state_mask;
     pending_buffer_slots_.pop();
 
     // It's possible that the producer channel has expired. When this occurs,
     // ignore the producer channel.
     if (producer_channel == nullptr) {
-      ALOGW(
-          "ConsumerQueueChannel::OnConsumerQueueImportBuffers: producer "
-          "channel has already been expired.");
+      ALOGW("%s: producer channel has already been expired.", __FUNCTION__);
       continue;
     }
 
-    auto status = producer_channel->CreateConsumer(message);
+    auto status =
+        producer_channel->CreateConsumer(message, consumer_state_mask);
 
     // If no buffers are imported successfully, clear available and return an
     // error. Otherwise, return all consumer handles already imported
     // successfully, but keep available bits on, so that the client can retry
     // importing remaining consumer buffers.
     if (!status) {
-      ALOGE(
-          "ConsumerQueueChannel::OnConsumerQueueImportBuffers: Failed create "
-          "consumer: %s",
-          status.GetErrorMessage().c_str());
+      ALOGE("%s: Failed create consumer: %s", __FUNCTION__,
+            status.GetErrorMessage().c_str());
       if (buffer_handles.empty()) {
         ClearAvailable();
         return status.error_status();
diff --git a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
index 0442881..502c6d6 100644
--- a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
+++ b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
@@ -12,10 +12,14 @@
  public:
   DECLARE_META_INTERFACE(BufferHub);
 
+  static const char* getServiceName() { return "bufferhubd"; }
   virtual sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
                                          uint32_t layer_count, uint32_t format,
                                          uint64_t usage,
                                          uint64_t user_metadata_size) = 0;
+
+  virtual status_t importBuffer(uint64_t token,
+                                sp<IBufferClient>* outClient) = 0;
 };
 
 class BnBufferHub : public BnInterface<IBufferHub> {
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
index e9bdb37..744c095 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
@@ -33,9 +33,6 @@
   void HandleImpulse(pdx::Message& message) override;
 
  private:
-  // Creates a detached buffer from existing IonBuffers.
-  BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
-                IonBuffer buffer, size_t user_metadata_size);
 
   // Allocates a new detached buffer.
   BufferChannel(BufferHubService* service, int buffer_id, uint32_t width,
@@ -55,7 +52,7 @@
   std::shared_ptr<BufferNode> buffer_node_ = nullptr;
 
   // The state bit of this buffer. Must be one the lower 63 bits.
-  uint64_t buffer_state_bit_ = 0ULL;
+  uint64_t client_state_mask_ = 0ULL;
 };
 
 }  // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_client.h b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
index 20d51ee..d79ec0a 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_client.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
@@ -7,19 +7,31 @@
 namespace android {
 namespace dvr {
 
+// Forward declaration to avoid circular dependency
+class BufferHubBinderService;
+
 class BufferClient : public BnBufferClient {
  public:
   // Creates a server-side buffer client from an existing BufferNode. Note that
   // this funciton takes ownership of the shared_ptr.
-  explicit BufferClient(std::shared_ptr<BufferNode> node)
-      : buffer_node_(std::move(node)){};
+  explicit BufferClient(std::shared_ptr<BufferNode> node,
+                        BufferHubBinderService* service)
+      : service_(service), buffer_node_(std::move(node)){};
 
   // Binder IPC functions
   bool isValid() override {
     return buffer_node_ ? buffer_node_->IsValid() : false;
   };
 
+  status_t duplicate(uint64_t* outToken) override;
+
  private:
+  // Hold a pointer to the service to bypass binder interface, as BufferClient
+  // and the service will be in the same process. Also, since service owns
+  // Client, if service dead the clients will be destroyed, so this pointer is
+  // guaranteed to be valid.
+  BufferHubBinderService* service_;
+
   std::shared_ptr<BufferNode> buffer_node_;
 };
 
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
index 11272ae..cf6124b 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
@@ -1,12 +1,15 @@
 #ifndef ANDROID_DVR_BUFFER_HUB_BINDER_H
 #define ANDROID_DVR_BUFFER_HUB_BINDER_H
 
+#include <random>
+#include <unordered_map>
 #include <vector>
 
 #include <binder/BinderService.h>
 #include <private/dvr/IBufferHub.h>
 #include <private/dvr/buffer_client.h>
 #include <private/dvr/buffer_hub.h>
+#include <private/dvr/buffer_node.h>
 
 namespace android {
 namespace dvr {
@@ -15,13 +18,14 @@
                                public BnBufferHub {
  public:
   static status_t start(const std::shared_ptr<BufferHubService>& pdx_service);
-  static const char* getServiceName() { return "bufferhubd"; }
-  // Dump bufferhub related information to given fd (usually stdout)
+  // Dumps bufferhub related information to given fd (usually stdout)
   // usage: adb shell dumpsys bufferhubd
   virtual status_t dump(int fd, const Vector<String16>& args) override;
 
-  // Helper function to get the BpReference to this service
-  static sp<IBufferHub> getServiceProxy();
+  // Marks a BufferNode to be duplicated.
+  // TODO(b/116681016): add importToken(int64_t)
+  status_t registerToken(const std::weak_ptr<BufferNode> node,
+                         uint64_t* outToken);
 
   // Binder IPC functions
   sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
@@ -29,10 +33,18 @@
                                  uint64_t usage,
                                  uint64_t user_metadata_size) override;
 
+  status_t importBuffer(uint64_t token, sp<IBufferClient>* outClient) override;
+
  private:
   std::shared_ptr<BufferHubService> pdx_service_;
 
   std::vector<sp<BufferClient>> client_list_;
+
+  // TODO(b/118180214): use a more secure implementation
+  std::mt19937_64 token_engine_;
+  // The mapping from token to a specific node. This is a many-to-one mapping.
+  // One node could be refered by 0 to multiple tokens.
+  std::unordered_map<uint64_t, std::weak_ptr<BufferNode>> token_map_;
 };
 
 }  // namespace dvr
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_node.h b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
index e1e8057..997aeda 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_node.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
@@ -1,77 +1,14 @@
 #ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
 #define ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+// TODO(b/118891412) Remove this file
 
-#include <private/dvr/ion_buffer.h>
-#include <ui/BufferHubMetadata.h>
+#include <bufferhub/BufferNode.h>
 
 namespace android {
 namespace dvr {
 
-class BufferNode {
- public:
-  // Creates a BufferNode from existing IonBuffers, i.e. creating from an
-  // existing ProducerChannel. Allocate a new BufferHubMetadata.
-  BufferNode(IonBuffer buffer, size_t user_metadata_size);
-
-  // Allocates a new BufferNode.
-  BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
-             uint32_t format, uint64_t usage, size_t user_metadata_size);
-
-  // Returns whether the object holds a valid graphic buffer.
-  bool IsValid() const { return buffer_.IsValid() && metadata_.IsValid(); }
-
-  size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
-
-  // Accessors of the IonBuffer.
-  IonBuffer& buffer() { return buffer_; }
-  const IonBuffer& buffer() const { return buffer_; }
-
-  // Accessors of metadata.
-  const BufferHubMetadata& metadata() const { return metadata_; }
-
-  // Gets the current value of active_clients_bit_mask in metadata_ with
-  // std::memory_order_acquire, so that all previous releases of
-  // active_clients_bit_mask from all threads will be returned here.
-  uint64_t GetActiveClientsBitMask() const;
-
-  // Find and add a new buffer_state_bit to active_clients_bit_mask in
-  // metadata_.
-  // Return the new buffer_state_bit that is added to active_clients_bit_mask.
-  // Return 0ULL if there are already 32 bp clients of the buffer.
-  uint64_t AddNewActiveClientsBitToMask();
-
-  // Removes the value from active_clients_bit_mask in metadata_ with
-  // std::memory_order_release, so that the change will be visible to any
-  // acquire of active_clients_bit_mask_ in any threads after the succeed of
-  // this operation.
-  void RemoveClientsBitFromMask(const uint64_t& value);
-
- private:
-  // Helper method for constructors to initialize atomic metadata header
-  // variables in shared memory.
-  void InitializeMetadata();
-
-  // Gralloc buffer handles.
-  IonBuffer buffer_;
-
-  // Metadata in shared memory.
-  BufferHubMetadata metadata_;
-
-  // The following variables are atomic variables in metadata_ that are visible
-  // to Bn object and Bp objects. Please find more info in
-  // BufferHubDefs::MetadataHeader.
-
-  // buffer_state_ tracks the state of the buffer. Buffer can be in one of these
-  // four states: gained, posted, acquired, released.
-  std::atomic<uint64_t>* buffer_state_ = nullptr;
-
-  // TODO(b/112012161): add comments to fence_state_.
-  std::atomic<uint64_t>* fence_state_ = nullptr;
-
-  // active_clients_bit_mask_ tracks all the bp clients of the buffer. It is the
-  // union of all buffer_state_bit of all bp clients.
-  std::atomic<uint64_t>* active_clients_bit_mask_ = nullptr;
-};
+typedef android::frameworks::bufferhub::V1_0::implementation::BufferNode
+    BufferNode;
 
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
index 84f664d..3298529 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
@@ -16,14 +16,14 @@
   using Message = pdx::Message;
 
   ConsumerChannel(BufferHubService* service, int buffer_id, int channel_id,
-                  uint64_t consumer_state_bit,
+                  uint64_t client_state_mask,
                   const std::shared_ptr<Channel> producer);
   ~ConsumerChannel() override;
 
   bool HandleMessage(Message& message) override;
   void HandleImpulse(Message& message) override;
 
-  uint64_t consumer_state_bit() const { return consumer_state_bit_; }
+  uint64_t client_state_mask() const { return client_state_mask_; }
   BufferInfo GetBufferInfo() const override;
 
   bool OnProducerPosted();
@@ -38,7 +38,7 @@
   pdx::Status<void> OnConsumerRelease(Message& message,
                                       LocalFence release_fence);
 
-  uint64_t consumer_state_bit_{0};
+  uint64_t client_state_mask_{0};
   bool acquired_{false};
   bool released_{true};
   std::weak_ptr<Channel> producer_;
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
index d98dbbc..3a81b03 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
@@ -3,8 +3,8 @@
 
 #include <queue>
 
-#include <private/dvr/bufferhub_rpc.h>
 #include <private/dvr/buffer_hub.h>
+#include <private/dvr/bufferhub_rpc.h>
 #include <private/dvr/consumer_channel.h>
 #include <private/dvr/producer_queue_channel.h>
 
@@ -28,7 +28,8 @@
   // Called by ProdcuerQueueChannel to notify consumer queue that a new
   // buffer has been allocated.
   void RegisterNewBuffer(
-      const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot);
+      const std::shared_ptr<ProducerChannel>& producer_channel,
+      size_t producer_slot);
 
   // Called after clients been signaled by service that new buffer has been
   // allocated. Clients uses kOpConsumerQueueImportBuffers to import new
@@ -40,14 +41,29 @@
   void OnProducerClosed();
 
  private:
+  // Data structure to store relavant info of a newly allocated producer buffer
+  // so that consumer channel and buffer can be created later.
+  struct PendingBuffer {
+    PendingBuffer(std::shared_ptr<ProducerChannel> channel, size_t slot,
+                  uint64_t mask) {
+      producer_channel = channel;
+      producer_slot = slot;
+      consumer_state_mask = mask;
+    }
+    PendingBuffer() = delete;
+
+    std::weak_ptr<ProducerChannel> producer_channel;
+    size_t producer_slot;
+    uint64_t consumer_state_mask;
+  };
+
   std::shared_ptr<ProducerQueueChannel> GetProducer() const;
 
-  // Pointer to the prodcuer channel
+  // Pointer to the producer channel.
   std::weak_ptr<Channel> producer_;
 
   // Tracks newly allocated buffer producers along with it's slot number.
-  std::queue<std::pair<std::weak_ptr<ProducerChannel>, size_t>>
-      pending_buffer_slots_;
+  std::queue<PendingBuffer> pending_buffer_slots_;
 
   // Tracks how many buffers have this queue imported.
   size_t capacity_;
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index 18bb7bf..3ad9c70 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -42,16 +42,20 @@
 
   ~ProducerChannel() override;
 
-  uint64_t buffer_state() const { return buffer_state_->load(); }
+  uint64_t buffer_state() const {
+    return buffer_state_->load(std::memory_order_acquire);
+  }
 
   bool HandleMessage(Message& message) override;
   void HandleImpulse(Message& message) override;
 
   BufferInfo GetBufferInfo() const override;
 
-  BufferDescription<BorrowedHandle> GetBuffer(uint64_t buffer_state_bit);
+  BufferDescription<BorrowedHandle> GetBuffer(uint64_t client_state_mask);
 
-  pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message);
+  pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message,
+                                                  uint64_t consumer_state_mask);
+  pdx::Status<uint64_t> CreateConsumerStateMask();
   pdx::Status<RemoteChannelHandle> OnNewConsumer(Message& message);
 
   pdx::Status<LocalFence> OnConsumerAcquire(Message& message);
@@ -91,7 +95,7 @@
   LocalFence post_fence_;
   LocalFence returned_fence_;
   size_t user_metadata_size_;  // size of user requested buffer buffer size.
-  size_t metadata_buf_size_;  // size of the ion buffer that holds metadata.
+  size_t metadata_buf_size_;   // size of the ion buffer that holds metadata.
 
   pdx::LocalHandle acquire_fence_fd_;
   pdx::LocalHandle release_fence_fd_;
@@ -108,7 +112,10 @@
   pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message);
   pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence);
   pdx::Status<LocalFence> OnProducerGain(Message& message);
-  pdx::Status<RemoteChannelHandle> OnProducerDetach(Message& message);
+
+  // Remove consumer from atomics in shared memory based on consumer_state_mask.
+  // This function is used for clean up for failures in CreateConsumer method.
+  void RemoveConsumerClientMask(uint64_t consumer_state_mask);
 
   ProducerChannel(const ProducerChannel&) = delete;
   void operator=(const ProducerChannel&) = delete;
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 581390f..c6e8ea9 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -100,6 +100,12 @@
   active_clients_bit_mask_ =
       new (&metadata_header_->active_clients_bit_mask) std::atomic<uint64_t>(0);
 
+  // Producer channel is never created after consumer channel, and one buffer
+  // only have one fixed producer for now. Thus, it is correct to assume
+  // producer state bit is kFirstClientBitMask for now.
+  active_clients_bit_mask_->store(BufferHubDefs::kFirstClientBitMask,
+                                  std::memory_order_release);
+
   acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
   release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
   if (!acquire_fence_fd_ || !release_fence_fd_) {
@@ -161,7 +167,8 @@
   ALOGD_IF(TRACE,
            "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
            "state=%" PRIx64 ".",
-           channel_id(), buffer_id(), buffer_state_->load());
+           channel_id(), buffer_id(),
+           buffer_state_->load(std::memory_order_acquire));
   for (auto consumer : consumer_channels_) {
     consumer->OnProducerClosed();
   }
@@ -170,14 +177,15 @@
 
 BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
   // Derive the mask of signaled buffers in this producer / consumer set.
-  uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
+  uint64_t signaled_mask = signaled() ? BufferHubDefs::kFirstClientBitMask : 0;
   for (const ConsumerChannel* consumer : consumer_channels_) {
-    signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
+    signaled_mask |= consumer->signaled() ? consumer->client_state_mask() : 0;
   }
 
   return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
                     buffer_.height(), buffer_.layer_count(), buffer_.format(),
-                    buffer_.usage(), pending_consumers_, buffer_state_->load(),
+                    buffer_.usage(), pending_consumers_,
+                    buffer_state_->load(std::memory_order_acquire),
                     signaled_mask, metadata_header_->queue_index);
 }
 
@@ -216,23 +224,18 @@
           *this, &ProducerChannel::OnProducerGain, message);
       return true;
 
-    case BufferHubRPC::ProducerBufferDetach::Opcode:
-      DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
-          *this, &ProducerChannel::OnProducerDetach, message);
-      return true;
-
     default:
       return false;
   }
 }
 
 BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
-    uint64_t buffer_state_bit) {
+    uint64_t client_state_mask) {
   return {buffer_,
           metadata_buffer_,
           buffer_id(),
           channel_id(),
-          buffer_state_bit,
+          client_state_mask,
           acquire_fence_fd_.Borrow(),
           release_fence_fd_.Borrow()};
 }
@@ -241,11 +244,73 @@
     Message& /*message*/) {
   ATRACE_NAME("ProducerChannel::OnGetBuffer");
   ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
-           buffer_id(), buffer_state_->load());
-  return {GetBuffer(BufferHubDefs::kProducerStateBit)};
+           buffer_id(), buffer_state_->load(std::memory_order_acquire));
+  return {GetBuffer(BufferHubDefs::kFirstClientBitMask)};
 }
 
-Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
+Status<uint64_t> ProducerChannel::CreateConsumerStateMask() {
+  // Try find the next consumer state bit which has not been claimed by any
+  // consumer yet.
+  // memory_order_acquire is chosen here because all writes in other threads
+  // that release active_clients_bit_mask_ need to be visible here.
+  uint64_t current_active_clients_bit_mask =
+      active_clients_bit_mask_->load(std::memory_order_acquire);
+  uint64_t client_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
+      current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
+  if (client_state_mask == 0ULL) {
+    ALOGE(
+        "ProducerChannel::CreateConsumer: reached the maximum mumber of "
+        "consumers per producer: 63.");
+    return ErrorStatus(E2BIG);
+  }
+  uint64_t updated_active_clients_bit_mask =
+      current_active_clients_bit_mask | client_state_mask;
+  // Set the updated value only if the current value stays the same as what was
+  // read before. If the comparison succeeds, update the value without
+  // reordering anything before or after this read-modify-write in the current
+  // thread, and the modification will be visible in other threads that acquire
+  // active_clients_bit_mask_. If the comparison fails, load the result of
+  // all writes from all threads to updated_active_clients_bit_mask.
+  // Keep on finding the next available slient state mask until succeed or out
+  // of memory.
+  while (!active_clients_bit_mask_->compare_exchange_weak(
+      current_active_clients_bit_mask, updated_active_clients_bit_mask,
+      std::memory_order_acq_rel, std::memory_order_acquire)) {
+    ALOGE("Current active clients bit mask is changed to %" PRIx64
+          ", which was expected to be %" PRIx64
+          ". Trying to generate a new client state mask to resolve race "
+          "condition.",
+          updated_active_clients_bit_mask, current_active_clients_bit_mask);
+    client_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
+        current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
+    if (client_state_mask == 0ULL) {
+      ALOGE(
+          "ProducerChannel::CreateConsumer: reached the maximum mumber of "
+          "consumers per producer: 63.");
+      return ErrorStatus(E2BIG);
+    }
+    updated_active_clients_bit_mask =
+        current_active_clients_bit_mask | client_state_mask;
+  }
+
+  return {client_state_mask};
+}
+
+void ProducerChannel::RemoveConsumerClientMask(uint64_t consumer_state_mask) {
+  // Clear up the buffer state and fence state in case there is already
+  // something there due to possible race condition between producer post and
+  // consumer failed to create channel.
+  buffer_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
+  fence_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
+
+  // Restore the consumer state bit and make it visible in other threads that
+  // acquire the active_clients_bit_mask_.
+  active_clients_bit_mask_->fetch_and(~consumer_state_mask,
+                                      std::memory_order_release);
+}
+
+Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(
+    Message& message, uint64_t consumer_state_mask) {
   ATRACE_NAME("ProducerChannel::CreateConsumer");
   ALOGD_IF(TRACE,
            "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
@@ -257,60 +322,28 @@
     ALOGE(
         "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
         status.GetErrorMessage().c_str());
+    RemoveConsumerClientMask(consumer_state_mask);
     return ErrorStatus(ENOMEM);
   }
 
-  // Try find the next consumer state bit which has not been claimed by any
-  // consumer yet.
-  // memory_order_acquire is chosen here because all writes in other threads
-  // that release active_clients_bit_mask_ need to be visible here.
-  uint64_t current_active_clients_bit_mask =
-      active_clients_bit_mask_->load(std::memory_order_acquire);
-  uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
-      current_active_clients_bit_mask | orphaned_consumer_bit_mask_ |
-      BufferHubDefs::kProducerStateBit);
-  if (consumer_state_bit == 0ULL) {
-    ALOGE(
-        "ProducerChannel::CreateConsumer: reached the maximum mumber of "
-        "consumers per producer: 63.");
-    return ErrorStatus(E2BIG);
-  }
-
-  uint64_t updated_active_clients_bit_mask =
-      current_active_clients_bit_mask | consumer_state_bit;
-  // Set the updated value only if the current value stays the same as what was
-  // read before. If the comparison succeeds, update the value without
-  // reordering anything before or after this read-modify-write in the current
-  // thread, and the modification will be visible in other threads that acquire
-  // active_clients_bit_mask_. If the comparison fails, load the result of
-  // all writes from all threads to updated_active_clients_bit_mask.
-  if (!active_clients_bit_mask_->compare_exchange_weak(
-          current_active_clients_bit_mask, updated_active_clients_bit_mask,
-          std::memory_order_acq_rel, std::memory_order_acquire)) {
-    ALOGE("Current active clients bit mask is changed to %" PRIu64
-          ", which was expected to be %" PRIu64 ".",
-          updated_active_clients_bit_mask, current_active_clients_bit_mask);
-    return ErrorStatus(EBUSY);
-  }
-
-  auto consumer =
-      std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
-                                        consumer_state_bit, shared_from_this());
+  auto consumer = std::make_shared<ConsumerChannel>(
+      service(), buffer_id(), channel_id, consumer_state_mask,
+      shared_from_this());
   const auto channel_status = service()->SetChannel(channel_id, consumer);
   if (!channel_status) {
     ALOGE(
         "ProducerChannel::CreateConsumer: failed to set new consumer channel: "
         "%s",
         channel_status.GetErrorMessage().c_str());
-    // Restore the consumer state bit and make it visible in other threads that
-    // acquire the active_clients_bit_mask_.
-    active_clients_bit_mask_->fetch_and(~consumer_state_bit,
-                                        std::memory_order_release);
+    RemoveConsumerClientMask(consumer_state_mask);
     return ErrorStatus(ENOMEM);
   }
 
+  uint64_t current_buffer_state =
+      buffer_state_->load(std::memory_order_acquire);
   if (!producer_owns_ &&
-      !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
+      (BufferHubDefs::IsBufferPosted(current_buffer_state) ||
+       BufferHubDefs::IsBufferAcquired(current_buffer_state))) {
     // Signal the new consumer when adding it to a posted producer.
     if (consumer->OnProducerPosted())
       pending_consumers_++;
@@ -322,7 +355,11 @@
 Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
   ATRACE_NAME("ProducerChannel::OnNewConsumer");
   ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
-  return CreateConsumer(message);
+  auto status = CreateConsumerStateMask();
+  if (!status.ok()) {
+    return status.error_status();
+  }
+  return CreateConsumer(message, /*consumer_state_mask=*/status.get());
 }
 
 Status<void> ProducerChannel::OnProducerPost(Message&,
@@ -403,13 +440,15 @@
   return {std::move(returned_fence_)};
 }
 
-Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
+// TODO(b/112338294) Keep here for reference. Remove it after new logic is
+// written.
+/* Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
     Message& message) {
   ATRACE_NAME("ProducerChannel::OnProducerDetach");
   ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
            buffer_id());
 
-  uint64_t buffer_state = buffer_state_->load();
+  uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
   if (!BufferHubDefs::IsBufferGained(buffer_state)) {
     // Can only detach a BufferProducer when it's in gained state.
     ALOGW(
@@ -455,7 +494,7 @@
   }
 
   return status;
-}
+} */
 
 Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
   ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
@@ -505,11 +544,11 @@
     // has to done by BufferHub as it requries synchronization among all
     // consumers.
     BufferHubDefs::ModifyBufferState(buffer_state_,
-                                     BufferHubDefs::kProducerStateBit, 0ULL);
+                                     BufferHubDefs::kFirstClientBitMask, 0ULL);
     ALOGD_IF(TRACE,
              "ProducerChannel::OnConsumerRelease: releasing last consumer: "
              "buffer_id=%d state=%" PRIx64 ".",
-             buffer_id(), buffer_state_->load());
+             buffer_id(), buffer_state_->load(std::memory_order_acquire));
 
     if (orphaned_consumer_bit_mask_) {
       ALOGW(
@@ -524,11 +563,12 @@
     SignalAvailable();
   }
 
-  ALOGE_IF(pending_consumers_ &&
-               BufferHubDefs::IsBufferReleased(buffer_state_->load()),
-           "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
-           "pending_consumers=%d, buffer buffer is in releaed state.",
-           pending_consumers_);
+  ALOGE_IF(
+      pending_consumers_ && BufferHubDefs::IsBufferReleased(
+                                buffer_state_->load(std::memory_order_acquire)),
+      "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
+      "pending_consumers=%d, buffer buffer is in releaed state.",
+      pending_consumers_);
   return {};
 }
 
@@ -549,25 +589,26 @@
   // Ignore the orphaned consumer.
   DecrementPendingConsumers();
 
-  const uint64_t consumer_state_bit = channel->consumer_state_bit();
-  ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
+  const uint64_t client_state_mask = channel->client_state_mask();
+  ALOGE_IF(orphaned_consumer_bit_mask_ & client_state_mask,
            "ProducerChannel::OnConsumerOrphaned: Consumer "
-           "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
-           consumer_state_bit);
-  orphaned_consumer_bit_mask_ |= consumer_state_bit;
+           "(client_state_mask=%" PRIx64 ") is already orphaned.",
+           client_state_mask);
+  orphaned_consumer_bit_mask_ |= client_state_mask;
 
   // Atomically clear the fence state bit as an orphaned consumer will never
   // signal a release fence. Also clear the buffer state as it won't be released
   // as well.
-  fence_state_->fetch_and(~consumer_state_bit);
-  BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
+  fence_state_->fetch_and(~client_state_mask);
+  BufferHubDefs::ModifyBufferState(buffer_state_, client_state_mask, 0ULL);
 
   ALOGW(
       "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
-      "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
+      "buffer_id=%d client_state_mask=%" PRIx64 " queue_index=%" PRIu64
       " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
-      buffer_id(), consumer_state_bit, metadata_header_->queue_index,
-      buffer_state_->load(), fence_state_->load());
+      buffer_id(), client_state_mask, metadata_header_->queue_index,
+      buffer_state_->load(std::memory_order_acquire),
+      fence_state_->load(std::memory_order_acquire));
 }
 
 void ProducerChannel::AddConsumer(ConsumerChannel* channel) {
@@ -579,10 +620,10 @@
       std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
   // Restore the consumer state bit and make it visible in other threads that
   // acquire the active_clients_bit_mask_.
-  active_clients_bit_mask_->fetch_and(~channel->consumer_state_bit(),
+  active_clients_bit_mask_->fetch_and(~channel->client_state_mask(),
                                       std::memory_order_release);
 
-  const uint64_t buffer_state = buffer_state_->load();
+  const uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
   if (BufferHubDefs::IsBufferPosted(buffer_state) ||
       BufferHubDefs::IsBufferAcquired(buffer_state)) {
     // The consumer client is being destoryed without releasing. This could
@@ -595,10 +636,11 @@
       BufferHubDefs::IsBufferGained(buffer_state)) {
     // The consumer is being close while it is suppose to signal a release
     // fence. Signal the dummy fence here.
-    if (fence_state_->load() & channel->consumer_state_bit()) {
+    if (fence_state_->load(std::memory_order_acquire) &
+        channel->client_state_mask()) {
       epoll_event event;
       event.events = EPOLLIN;
-      event.data.u64 = channel->consumer_state_bit();
+      event.data.u64 = channel->client_state_mask();
       if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
                     dummy_fence_fd_.Get(), &event) < 0) {
         ALOGE(
diff --git a/services/vr/bufferhubd/tests/Android.bp b/services/vr/bufferhubd/tests/Android.bp
index a80691f..a611268 100644
--- a/services/vr/bufferhubd/tests/Android.bp
+++ b/services/vr/bufferhubd/tests/Android.bp
@@ -24,30 +24,3 @@
     // TODO(b/117568153): Temporarily opt out using libcrt.
     no_libcrt: true,
 }
-
-cc_test {
-    name: "buffer_node-test",
-    srcs: ["buffer_node-test.cpp"],
-    cflags: [
-        "-DLOG_TAG=\"buffer_node-test\"",
-        "-DTRACE=0",
-        "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
-    ],
-    header_libs: ["libdvr_headers"],
-    static_libs: [
-        "libbufferhub",
-        "libbufferhubd",
-        "libgmock",
-    ],
-    shared_libs: [
-        "libbase",
-        "libbinder",
-        "liblog",
-        "libpdx_default_transport",
-        "libui",
-        "libutils",
-    ],
-    // TODO(b/117568153): Temporarily opt out using libcrt.
-    no_libcrt: true,
-}
-
diff --git a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
index c4703f1..7c00fa6 100644
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
@@ -1,7 +1,8 @@
+#include <binder/IServiceManager.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <private/dvr/IBufferClient.h>
-#include <private/dvr/buffer_hub_binder.h>
+#include <private/dvr/IBufferHub.h>
 #include <ui/PixelFormat.h>
 
 namespace android {
@@ -9,7 +10,7 @@
 
 namespace {
 
-using testing::Ne;
+using testing::IsNull;
 using testing::NotNull;
 
 const int kWidth = 640;
@@ -22,8 +23,10 @@
 class BufferHubBinderServiceTest : public ::testing::Test {
  protected:
   void SetUp() override {
-    service = BufferHubBinderService::getServiceProxy();
-    ASSERT_THAT(service, Ne(nullptr));
+    status_t ret = getService<IBufferHub>(
+        String16(IBufferHub::getServiceName()), &service);
+    ASSERT_EQ(ret, OK);
+    ASSERT_THAT(service, NotNull());
   }
 
   sp<IBufferHub> service;
@@ -36,6 +39,46 @@
   EXPECT_TRUE(bufferClient->isValid());
 }
 
+TEST_F(BufferHubBinderServiceTest, TestDuplicateAndImportBuffer) {
+  sp<IBufferClient> bufferClient = service->createBuffer(
+      kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+  ASSERT_THAT(bufferClient, NotNull());
+  EXPECT_TRUE(bufferClient->isValid());
+
+  uint64_t token1 = 0ULL;
+  status_t ret = bufferClient->duplicate(&token1);
+  EXPECT_EQ(ret, NO_ERROR);
+
+  // Tokens should be unique even corresponding to the same buffer
+  uint64_t token2 = 0ULL;
+  ret = bufferClient->duplicate(&token2);
+  EXPECT_EQ(ret, NO_ERROR);
+  EXPECT_NE(token2, token1);
+
+  sp<IBufferClient> bufferClient1;
+  ret = service->importBuffer(token1, &bufferClient1);
+  EXPECT_EQ(ret, NO_ERROR);
+  ASSERT_THAT(bufferClient1, NotNull());
+  EXPECT_TRUE(bufferClient1->isValid());
+
+  // Consumes the token to keep the service clean
+  sp<IBufferClient> bufferClient2;
+  ret = service->importBuffer(token2, &bufferClient2);
+  EXPECT_EQ(ret, NO_ERROR);
+  ASSERT_THAT(bufferClient2, NotNull());
+  EXPECT_TRUE(bufferClient2->isValid());
+}
+
+TEST_F(BufferHubBinderServiceTest, TestImportUnexistingToken) {
+  // There is very little chance that this test fails if there is a token = 0
+  // in the service.
+  uint64_t unexistingToken = 0ULL;
+  sp<IBufferClient> bufferClient;
+  status_t ret = service->importBuffer(unexistingToken, &bufferClient);
+  EXPECT_EQ(ret, PERMISSION_DENIED);
+  EXPECT_THAT(bufferClient, IsNull());
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/services/vr/bufferhubd/tests/buffer_node-test.cpp b/services/vr/bufferhubd/tests/buffer_node-test.cpp
deleted file mode 100644
index c2526fe..0000000
--- a/services/vr/bufferhubd/tests/buffer_node-test.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#include <errno.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <private/dvr/buffer_node.h>
-
-namespace android {
-namespace dvr {
-
-namespace {
-
-const uint32_t kWidth = 640;
-const uint32_t kHeight = 480;
-const uint32_t kLayerCount = 1;
-const uint32_t kFormat = 1;
-const uint64_t kUsage = 0;
-const size_t kUserMetadataSize = 0;
-
-class BufferNodeTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    buffer_node = new BufferNode(kWidth, kHeight, kLayerCount, kFormat, kUsage,
-                                 kUserMetadataSize);
-    ASSERT_TRUE(buffer_node->IsValid());
-  }
-
-  void TearDown() override {
-    if (buffer_node != nullptr) {
-      delete buffer_node;
-    }
-  }
-
-  BufferNode* buffer_node = nullptr;
-};
-
-TEST_F(BufferNodeTest, TestCreateBufferNode) {
-  EXPECT_EQ(buffer_node->user_metadata_size(), kUserMetadataSize);
-}
-
-TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_twoNewClients) {
-  uint64_t new_buffer_state_bit_1 = buffer_node->AddNewActiveClientsBitToMask();
-  EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), new_buffer_state_bit_1);
-
-  // Request and add a new buffer_state_bit again.
-  // Active clients bit mask should be the union of the two new
-  // buffer_state_bits.
-  uint64_t new_buffer_state_bit_2 = buffer_node->AddNewActiveClientsBitToMask();
-  EXPECT_EQ(buffer_node->GetActiveClientsBitMask(),
-            new_buffer_state_bit_1 | new_buffer_state_bit_2);
-}
-
-TEST_F(BufferNodeTest, TestAddNewActiveClientsBitToMask_32NewClients) {
-  uint64_t new_buffer_state_bit = 0ULL;
-  uint64_t current_mask = 0ULL;
-  uint64_t expected_mask = 0ULL;
-
-  for (int i = 0; i < 64; ++i) {
-    new_buffer_state_bit = buffer_node->AddNewActiveClientsBitToMask();
-    EXPECT_NE(new_buffer_state_bit, 0);
-    EXPECT_FALSE(new_buffer_state_bit & current_mask);
-    expected_mask = current_mask | new_buffer_state_bit;
-    current_mask = buffer_node->GetActiveClientsBitMask();
-    EXPECT_EQ(current_mask, expected_mask);
-  }
-
-  // Method should fail upon requesting for more than maximum allowable clients.
-  new_buffer_state_bit = buffer_node->AddNewActiveClientsBitToMask();
-  EXPECT_EQ(new_buffer_state_bit, 0ULL);
-  EXPECT_EQ(errno, E2BIG);
-}
-
-TEST_F(BufferNodeTest, TestRemoveActiveClientsBitFromMask) {
-  buffer_node->AddNewActiveClientsBitToMask();
-  uint64_t current_mask = buffer_node->GetActiveClientsBitMask();
-  uint64_t new_buffer_state_bit = buffer_node->AddNewActiveClientsBitToMask();
-  EXPECT_NE(buffer_node->GetActiveClientsBitMask(), current_mask);
-
-  buffer_node->RemoveClientsBitFromMask(new_buffer_state_bit);
-  EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
-
-  // Remove the test_mask again to the active client bit mask should not modify
-  // the value of active clients bit mask.
-  buffer_node->RemoveClientsBitFromMask(new_buffer_state_bit);
-  EXPECT_EQ(buffer_node->GetActiveClientsBitMask(), current_mask);
-}
-
-}  // namespace
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 003775b..258b45b 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -55,7 +55,6 @@
     "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
     "-Wall",
     "-Werror",
-    // mVrClient unused in vr_composer_client.cpp
     "-Wno-error=unused-private-field",
     // Warnings in vr_hwc.cpp to be fixed after sync of goog/master.
     "-Wno-sign-compare",
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index 4b90031..786d5fa 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -19,6 +19,8 @@
 #include <hardware/gralloc1.h>
 #include <log/log.h>
 
+#include <memory>
+
 #include "impl/vr_hwc.h"
 #include "impl/vr_composer_client.h"
 
@@ -39,11 +41,11 @@
 
 std::unique_ptr<ComposerCommandEngine>
 VrComposerClient::createCommandEngine() {
-  return std::unique_ptr<VrCommandEngine>(new VrCommandEngine(*this));
+  return std::make_unique<VrCommandEngine>(*this);
 }
 
 VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client)
-    : ComposerCommandEngine(client.mHal, client.mResources.get()), mVrClient(client),
+    : ComposerCommandEngine(client.mHal, client.mResources.get()),
       mVrHal(client.mVrHal) {}
 
 VrComposerClient::VrCommandEngine::~VrCommandEngine() {}
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index 76b1c4f..de22640 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -54,7 +54,6 @@
 
     IVrComposerClient::BufferMetadata readBufferMetadata();
 
-    VrComposerClient& mVrClient;
     android::dvr::VrHwc& mVrHal;
 
     VrCommandEngine(const VrCommandEngine&) = delete;
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index 4065785..a24c889 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -12,16 +12,16 @@
 #include <thread>
 #include <utility>
 
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <dvr/performance_client_api.h>
 #include <gtest/gtest.h>
 #include <private/android_filesystem_config.h>
 
 #include "stdio_filebuf.h"
-#include "string_trim.h"
 #include "unique_file.h"
 
-using android::dvr::Trim;
+using android::base::Trim;
 using android::dvr::UniqueFile;
 using android::dvr::stdio_filebuf;
 
diff --git a/services/vr/performanced/string_trim.h b/services/vr/performanced/string_trim.h
deleted file mode 100644
index 7094e9f..0000000
--- a/services/vr/performanced/string_trim.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
-#define ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
-
-#include <functional>
-#include <locale>
-#include <string>
-
-namespace android {
-namespace dvr {
-
-// Trims whitespace from the left side of |subject| and returns the result as a
-// new string.
-inline std::string LeftTrim(std::string subject) {
-  subject.erase(subject.begin(),
-                std::find_if(subject.begin(), subject.end(),
-                             std::not1(std::ptr_fun<int, int>(std::isspace))));
-  return subject;
-}
-
-// Trims whitespace from the right side of |subject| and returns the result as a
-// new string.
-inline std::string RightTrim(std::string subject) {
-  subject.erase(std::find_if(subject.rbegin(), subject.rend(),
-                             std::not1(std::ptr_fun<int, int>(std::isspace)))
-                    .base(),
-                subject.end());
-  return subject;
-}
-
-// Trims whitespace from the both sides of |subject| and returns the result as a
-// new string.
-inline std::string Trim(std::string subject) {
-  subject.erase(subject.begin(),
-                std::find_if(subject.begin(), subject.end(),
-                             std::not1(std::ptr_fun<int, int>(std::isspace))));
-  subject.erase(std::find_if(subject.rbegin(), subject.rend(),
-                             std::not1(std::ptr_fun<int, int>(std::isspace)))
-                    .base(),
-                subject.end());
-  return subject;
-}
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp
index bda1682..2fc96bf 100644
--- a/services/vr/performanced/task.cpp
+++ b/services/vr/performanced/task.cpp
@@ -10,10 +10,10 @@
 #include <memory>
 #include <sstream>
 
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 
 #include "stdio_filebuf.h"
-#include "string_trim.h"
 
 namespace {
 
@@ -102,7 +102,7 @@
 
       // The status file has lines with the format <field>:<value>. Extract the
       // value after the colon.
-      return Trim(line.substr(offset + field.size() + 1));
+      return android::base::Trim(line.substr(offset + field.size() + 1));
     }
   }
 
@@ -123,7 +123,7 @@
       }
 
       std::string key = line.substr(0, offset);
-      std::string value = Trim(line.substr(offset + 1));
+      std::string value = android::base::Trim(line.substr(offset + 1));
 
       ALOGD_IF(TRACE, "Task::ReadStatusFields: key=\"%s\" value=\"%s\"",
                key.c_str(), value.c_str());
@@ -156,7 +156,7 @@
     std::string line = "";
     std::getline(file_stream, line);
 
-    return Trim(line);
+    return android::base::Trim(line);
   } else {
     return "";
   }
diff --git a/vulkan/api/platform.api b/vulkan/api/platform.api
index 41f398d..a7c4c30 100644
--- a/vulkan/api/platform.api
+++ b/vulkan/api/platform.api
@@ -56,3 +56,6 @@
 
 // VK_USE_PLATFORM_XLIB_XRANDR_EXT
 @internal type u64 RROutput
+
+// VK_USE_PLATFORM_FUCHSIA
+@internal type u32 zx_handle_t
\ No newline at end of file
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 5722810..8f76606 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
 // API version (major.minor.patch)
 define VERSION_MAJOR 1
 define VERSION_MINOR 1
-define VERSION_PATCH 86
+define VERSION_PATCH 91
 
 // API limits
 define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -85,9 +85,7 @@
 @extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6
 @extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_NAME         "VK_KHR_wayland_surface"
 
-// 8
-@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_SPEC_VERSION         4
-@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_NAME                 "VK_KHR_mir_surface"
+// 8 - VK_KHR_mir_surface removed
 
 // 9
 @extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6
@@ -149,6 +147,10 @@
 @extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1
 @extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc"
 
+// 29
+@extension("VK_EXT_transform_feedback") define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1
+@extension("VK_EXT_transform_feedback") define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback"
+
 // 34
 @extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
 @extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
@@ -501,6 +503,10 @@
 @extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_SPEC_VERSION 1
 @extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_EXTENSION_NAME "VK_KHR_bind_memory2"
 
+// 159
+@extension("VK_EXT_image_drm_format_modifier") define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1
+@extension("VK_EXT_image_drm_format_modifier") define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier"
+
 // 161
 @extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1
 @extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache"
@@ -518,8 +524,8 @@
 @extension("VK_NV_shading_rate_image") define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image"
 
 // 166
-@extension("VK_NVX_raytracing") define VK_NVX_RAYTRACING_SPEC_VERSION 1
-@extension("VK_NVX_raytracing") define VK_NVX_RAYTRACING_EXTENSION_NAME "VK_NVX_raytracing"
+@extension("VK_NV_raytracing") define VK_NV_RAYTRACING_SPEC_VERSION 2
+@extension("VK_NV_raytracing") define VK_NV_RAYTRACING_EXTENSION_NAME "VK_NV_raytracing"
 
 // 167
 @extension("VK_NV_representative_fragment_test") define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 1
@@ -557,6 +563,10 @@
 @extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1
 @extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties"
 
+// 190
+@extension("VK_AMD_memory_overallocation_behavior") define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1
+@extension("VK_AMD_memory_overallocation_behavior") define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior"
+
 // 191
 @extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
 @extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
@@ -597,6 +607,22 @@
 @extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2
 @extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model"
 
+// 213
+@extension("VK_EXT_pci_bus_info") define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 1
+@extension("VK_EXT_pci_bus_info") define VK_EXT_PCI_BUS_INFO_EXENSION_NAME "VK_EXT_pci_bus_info"
+
+// 215
+@extension("VK_FUCHSIA_imagepipe_surface") define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1
+@extension("VK_FUCHSIA_imagepipe_surface") define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface"
+
+// 224
+@extension("VK_GOOGLE_hlsl_functionality1") define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 0
+@extension("VK_GOOGLE_hlsl_functionality1") define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1"
+
+// 225
+@extension("VK_GOOGLE_decorate_string") define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 0
+@extension("VK_GOOGLE_decorate_string") define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string"
+
 /////////////
 //  Types  //
 /////////////
@@ -669,7 +695,7 @@
 @extension("VK_EXT_validation_cache") @nonDispatchHandle type u64 VkValidationCacheEXT
 
 // 166
-@extension("VK_NVX_raytracing") @nonDispatchHandle type u64 VkAccelerationStructureNVX
+@extension("VK_NV_raytracing") @nonDispatchHandle type u64 VkAccelerationStructureNV
 
 /////////////
 //  Enums  //
@@ -724,6 +750,9 @@
 enum VkImageTiling {
     VK_IMAGE_TILING_OPTIMAL                                 = 0x00000000,
     VK_IMAGE_TILING_LINEAR                                  = 0x00000001,
+
+    //@extension("VK_EXT_image_drm_format_modifier") // 159
+    VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT                 = 1000158000,
 }
 
 enum VkImageViewType {
@@ -767,8 +796,8 @@
     //@extension("VK_EXT_inline_uniform_block") // 139
     VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT             = 1000138000,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NVX           = 1000165000,
+    //@extension("VK_NV_raytracing") // 166
+    VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV            = 1000165000,
 }
 
 enum VkQueryType {
@@ -776,8 +805,11 @@
     VK_QUERY_TYPE_PIPELINE_STATISTICS                       = 0x00000001, /// Optional
     VK_QUERY_TYPE_TIMESTAMP                                 = 0x00000002,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_QUERY_TYPE_COMPACTED_SIZE_NVX                        = 1000165000,
+    //@extension("VK_EXT_transform_feedback") // 29
+    VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT             = 1000028004,
+
+    //@extension("VK_NV_raytracing") // 166
+    VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV  = 1000165000,
 }
 
 enum VkBorderColor {
@@ -793,8 +825,8 @@
     VK_PIPELINE_BIND_POINT_GRAPHICS                         = 0x00000000,
     VK_PIPELINE_BIND_POINT_COMPUTE                          = 0x00000001,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_PIPELINE_BIND_POINT_RAYTRACING_NVX                   = 1000165000,
+    //@extension("VK_NV_raytracing") // 166
+    VK_PIPELINE_BIND_POINT_RAY_TRACING_NV                   = 1000165000,
 }
 
 enum VkPrimitiveTopology {
@@ -819,6 +851,9 @@
 enum VkIndexType {
     VK_INDEX_TYPE_UINT16                                    = 0x00000000,
     VK_INDEX_TYPE_UINT32                                    = 0x00000001,
+
+    //@extension("VK_NV_raytracing") // 166
+    VK_INDEX_TYPE_NONE_NV                                   = 1000165000,
 }
 
 enum VkFilter {
@@ -1417,9 +1452,6 @@
     //@extension("VK_KHR_wayland_surface") // 7
     VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR           = 1000006000,
 
-    //@extension("VK_KHR_mir_surface") // 8
-    VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR               = 1000007000,
-
     //@extension("VK_KHR_android_surface") // 9
     VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR           = 1000008000,
 
@@ -1447,6 +1479,11 @@
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
 
+    //@extension("VK_EXT_transform_feedback") // 29
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT       = 1000028000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT     = 1000028001,
+    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT   = 1000028002,
+
     //@extension("VK_AMD_texture_gather_bias_lod") // 42
     VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD  = 1000041000,
 
@@ -1722,6 +1759,14 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = 1000156004,
     VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR  = 1000156005,
 
+    //@extension("VK_EXT_image_drm_format_modifier") // 159
+    VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT               = 1000158000,
+    VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT                    = 1000158001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT    = 1000158002,
+    VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT        = 1000158003,
+    VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT    = 1000158004,
+    VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT              = 1000158005,
+
     //@extension("VK_KHR_bind_memory2") // 158
     VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR                       = 1000157000,
     VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR                        = 1000157001,
@@ -1743,18 +1788,18 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002,
     VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_STRUCTURE_TYPE_RAYTRACING_PIPELINE_CREATE_INFO_NVX = 1000165000,
-    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NVX = 1000165001,
-    VK_STRUCTURE_TYPE_GEOMETRY_INSTANCE_NVX = 1000165002,
-    VK_STRUCTURE_TYPE_GEOMETRY_NVX = 1000165003,
-    VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NVX = 1000165004,
-    VK_STRUCTURE_TYPE_GEOMETRY_AABB_NVX = 1000165005,
-    VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NVX = 1000165006,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_ACCELERATION_STRUCTURE_INFO_NVX = 1000165007,
-    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NVX = 1000165008,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAYTRACING_PROPERTIES_NVX = 1000165009,
-    VK_STRUCTURE_TYPE_HIT_SHADER_MODULE_CREATE_INFO_NVX = 1000165010,
+    //@extension("VK_NV_raytracing") // 166
+    VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV                   = 1000165000,
+    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV                 = 1000165001,
+    VK_STRUCTURE_TYPE_GEOMETRY_NV                                           = 1000165003,
+    VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV                                 = 1000165004,
+    VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV                                      = 1000165005,
+    VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV            = 1000165006,
+    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV        = 1000165007,
+    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV    = 1000165008,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV             = 1000165009,
+    VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV               = 1000165011,
+    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV                        = 1000165012,
 
     //@extension("VK_NV_representative_fragment_test") // 167
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000,
@@ -1778,12 +1823,18 @@
     //@extension("VK_KHR_shader_atomic_int64") // 181
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR  = 1000180000,
 
+    //@extension("VK_EXT_calibrated_timestamps") // 185
+    VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT                     = 1000184000,
+
     //@extension("VK_KHR_driver_properties") // 197
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR             = 1000196000,
 
     //@extension("VK_AMD_shader_core_properties") // 186
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD        = 1000185000,
 
+    //@extension("VK_AMD_memory_overallocation_behavior") // 190
+    VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD      = 1000189000,
+
     //@extension("VK_EXT_vertex_attribute_divisor") // 191
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT   = 1000190000,
     VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT       = 1000190001,
@@ -1795,6 +1846,12 @@
 
     //@extension("VK_KHR_vulkan_memory_model") // 212
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000,
+
+    //@extension("VK_EXT_pci_bus_info") // 213
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT       = 1000212000,
+
+    //@extension("VK_FUCHSIA_imagepipe_surface") // 215
+    VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA     = 1000214000,
 }
 
 enum VkSubpassContents {
@@ -1857,14 +1914,17 @@
     //@extension("VK_KHR_maintenance1") // 70
     VK_ERROR_OUT_OF_POOL_MEMORY_KHR                         = 0xC4642878, // -1000069000
 
-    //@extension("VK_EXT_global_priority") // 175
-    VK_ERROR_NOT_PERMITTED_EXT                              = 0xC4628E4F, // -1000174001
-
     //@extension("VK_KHR_external_memory") // 73
     VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR                    = 0xC4641CBD, // -1000072003
 
+    //@extension("VK_EXT_image_drm_format_modifier") // 159
+    VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT   = 0xC462CCD0, // -1000158000
+
     //@extension("VK_EXT_descriptor_indexing") // 162
     VK_ERROR_FRAGMENTATION_EXT                              = 0xc462c118, // -1000161000
+
+    //@extension("VK_EXT_global_priority") // 175
+    VK_ERROR_NOT_PERMITTED_EXT                              = 0xC4628E4F, // -1000174001
 }
 
 enum VkDynamicState {
@@ -1956,8 +2016,8 @@
     //@extension("VK_EXT_validation_cache") // 161
     VK_OBJECT_TYPE_VALIDATION_CACHE_EXT                     = 1000160000,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX               = 1000165000,
+    //@extension("VK_NV_raytracing") // 166
+    VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV                = 1000165000,
 }
 
 
@@ -2080,8 +2140,8 @@
     //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
     VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = 1000156000,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX_EXT  = 1000165000,
+    //@extension("VK_NV_raytracing") // 166
+    VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT   = 1000165000,
 }
 
 @extension("VK_AMD_rasterization_order") // 19
@@ -2256,22 +2316,36 @@
     VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV             = 3,
 }
 
-@extension("VK_NVX_raytracing") // 166
-enum VkGeometryTypeNVX {
-    VK_GEOMETRY_TYPE_TRIANGLES_NVX                          = 0,
-    VK_GEOMETRY_TYPE_AABBS_NVX                              = 1,
+@extension("VK_NV_raytracing") // 166
+enum VkRayTracingShaderGroupTypeNV {
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV                 = 0,
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV     = 1,
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV    = 2,
 }
 
-@extension("VK_NVX_raytracing") // 166
-enum VkAccelerationStructureTypeNVX {
-    VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX            = 0,
-    VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX         = 1,
+@extension("VK_NV_raytracing") // 166
+enum VkGeometryTypeNV {
+    VK_GEOMETRY_TYPE_TRIANGLES_NV                           = 0,
+    VK_GEOMETRY_TYPE_AABBS_NV                               = 1,
 }
 
-@extension("VK_NVX_raytracing") // 166
-enum VkCopyAccelerationStructureModeNVX {
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX           = 0,
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX         = 1,
+@extension("VK_NV_raytracing") // 166
+enum VkAccelerationStructureTypeNV {
+    VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV             = 0,
+    VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV          = 1,
+}
+
+@extension("VK_NV_raytracing") // 166
+enum VkCopyAccelerationStructureModeNV {
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV            = 0,
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV          = 1,
+}
+
+@extension("VK_NV_raytracing") // 166
+enum VkAccelerationStructureMemoryRequirementsTypeNV {
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV            = 0,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV     = 1,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV    = 2,
 }
 
 @extension("VK_EXT_global_priority") // 175
@@ -2282,6 +2356,21 @@
     VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT                   = 1024,
 }
 
+@extension("VK_EXT_calibrated_timestamps") // 185
+enum VkTimeDomainEXT {
+    VK_TIME_DOMAIN_DEVICE_EXT                               = 0,
+    VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT                      = 1,
+    VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT                  = 2,
+    VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT            = 3,
+}
+
+@extension("VK_AMD_memory_overallocation_behavior") // 190
+enum VkMemoryOverallocationBehaviorAMD {
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD           = 0,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD           = 1,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD        = 2,
+}
+
 @extension("VK_KHR_driver_properties") // 197
 enum VkDriverIdKHR {
     VK_DRIVER_ID_AMD_PROPRIETARY_KHR                        = 1,
@@ -2370,9 +2459,14 @@
     //@extension("VK_NV_shading_rate_image") // 165
     VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV                = 0x00800000,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NVX           = 0x00200000,
-    VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVX          = 0x00400000,
+    //@extension("VK_NV_raytracing") // 166
+    VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV            = 0x00200000,
+    VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV           = 0x00400000,
+
+    //@extension("VK_EXT_transform_feedback") // 29
+    VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT              = 0x02000000,
+    VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT       = 0x04000000,
+    VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT      = 0x08000000,
 }
 
 /// Buffer usage flags
@@ -2391,8 +2485,12 @@
     //@extension("VK_EXT_conditional_rendering") // 82
     VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT           = 0x00000200,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_BUFFER_USAGE_RAYTRACING_BIT_NVX                      = 0x00000400,
+    //@extension("VK_NV_raytracing") // 166
+    VK_BUFFER_USAGE_RAY_TRACING_BIT_NV                      = 0x00000400,
+
+    //@extension("VK_EXT_transform_feedback") // 29
+    VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT           = 0x00000800,
+    VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT   = 0x00001000,
 }
 
 /// Buffer creation flags
@@ -2419,13 +2517,13 @@
 
     VK_SHADER_STAGE_ALL                                     = 0x7FFFFFFF,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_SHADER_STAGE_RAYGEN_BIT_NVX                          = 0x00000100,
-    VK_SHADER_STAGE_ANY_HIT_BIT_NVX                         = 0x00000200,
-    VK_SHADER_STAGE_CLOSEST_HIT_BIT_NVX                     = 0x00000400,
-    VK_SHADER_STAGE_MISS_BIT_NVX                            = 0x00000800,
-    VK_SHADER_STAGE_INTERSECTION_BIT_NVX                    = 0x00001000,
-    VK_SHADER_STAGE_CALLABLE_BIT_NVX                        = 0x00002000,
+    //@extension("VK_NV_raytracing") // 166
+    VK_SHADER_STAGE_RAYGEN_BIT_NV                           = 0x00000100,
+    VK_SHADER_STAGE_ANY_HIT_BIT_NV                          = 0x00000200,
+    VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV                      = 0x00000400,
+    VK_SHADER_STAGE_MISS_BIT_NV                             = 0x00000800,
+    VK_SHADER_STAGE_INTERSECTION_BIT_NV                     = 0x00001000,
+    VK_SHADER_STAGE_CALLABLE_BIT_NV                         = 0x00002000,
 
     //@extension("VK_NV_mesh_shader") // 203
     VK_SHADER_STAGE_TASK_BIT_NV                             = 0x00000040,
@@ -2523,8 +2621,8 @@
     VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 0x00000008,
     VK_PIPELINE_CREATE_DISPATCH_BASE_KHR                    = 0x00000010,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NVX                = 0x00000020,
+    //@extension("VK_NV_raytracing") // 166
+    VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV                 = 0x00000020,
 }
 
 /// Color component flags
@@ -2666,6 +2764,12 @@
     VK_IMAGE_ASPECT_PLANE_0_BIT_KHR                         = 0x00000010,
     VK_IMAGE_ASPECT_PLANE_1_BIT_KHR                         = 0x00000020,
     VK_IMAGE_ASPECT_PLANE_2_BIT_KHR                         = 0x00000040,
+
+    //@extension("VK_EXT_transform_feedback") // 29
+    VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT                  = 0x00000080,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT                  = 0x00000100,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT                  = 0x00000200,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT                  = 0x00000400,
 }
 
 /// Sparse memory bind flags
@@ -2713,12 +2817,16 @@
     //@extension("VK_NV_shading_rate_image") // 165
     VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV             = 0x00400000,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_PIPELINE_STAGE_RAYTRACING_BIT_NVX                    = 0x00200000,
+    //@extension("VK_NV_raytracing") // 166
+    VK_PIPELINE_STAGE_RAY_TRACING_BIT_NV                    = 0x00200000,
+    VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV   = 0x02000000,
 
     //@extension("VK_NV_mesh_shader") // 203
     VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV                    = 0x00080000,
     VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV                    = 0x00100000,
+
+    //@extension("VK_EXT_transform_feedback") // 29
+    VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT            = 0x01000000,
 }
 
 /// Render pass attachment description flags
@@ -3113,12 +3221,6 @@
 //bitfield VkWaylandSurfaceCreateFlagBitsKHR {
 //}
 
-@extension("VK_KHR_mir_surface") // 8
-type VkFlags VkMirSurfaceCreateFlagsKHR
-//@extension("VK_KHR_mir_surface") // 8
-//bitfield VkMirSurfaceCreateFlagBitsKHR {
-//}
-
 @extension("VK_KHR_android_surface") // 9
 type VkFlags VkAndroidSurfaceCreateFlagsKHR
 //@extension("VK_KHR_android_surface") // 9
@@ -3149,6 +3251,12 @@
     VK_DEBUG_REPORT_DEBUG_BIT_EXT                           = 0x00000010,
 }
 
+@extension("VK_EXT_transform_feedback") // 29
+type VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT
+//@extension("VK_EXT_transform_feedback") // 29
+//bitfield VkPipelineRasterizationStateStreamCreateFlagBitsEXT {
+//}
+
 @extension("VK_NV_external_memory_capabilities") // 56
 type VkFlags VkExternalMemoryHandleTypeFlagsNV
 @extension("VK_NV_external_memory_capabilities") // 56
@@ -3397,35 +3505,41 @@
     VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT     = 0x00000008,
 }
 
-@extension("VK_NVX_raytracing") // 166
-type VkFlags VkGeometryFlagsNVX
-@extension("VK_NVX_raytracing") // 166
-bitfield VkGeometryFlagBitsNVX {
-    VK_GEOMETRY_OPAQUE_BIT_NVX                          = 0x00000001,
-    VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NVX = 0x00000002,
+@extension("VK_NV_raytracing") // 166
+type VkFlags VkGeometryFlagsNV
+@extension("VK_NV_raytracing") // 166
+bitfield VkGeometryFlagBitsNV {
+    VK_GEOMETRY_OPAQUE_BIT_NV                           = 0x00000001,
+    VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV  = 0x00000002,
 }
 
-@extension("VK_NVX_raytracing") // 166
-type VkFlags VkGeometryInstanceFlagsNVX
-@extension("VK_NVX_raytracing") // 166
-bitfield VkGeometryInstanceFlagBitsNVX {
-    VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NVX      = 0x00000001,
-    VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_FLIP_WINDING_BIT_NVX = 0x00000002,
-    VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NVX               = 0x00000004,
-    VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NVX            = 0x00000008,
+@extension("VK_NV_raytracing") // 166
+type VkFlags VkGeometryInstanceFlagsNV
+@extension("VK_NV_raytracing") // 166
+bitfield VkGeometryInstanceFlagBitsNV {
+    VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV           = 0x00000001,
+    VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002,
+    VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV                    = 0x00000004,
+    VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV                 = 0x00000008,
 }
 
-@extension("VK_NVX_raytracing") // 166
-type VkFlags VkBuildAccelerationStructureFlagsNVX
-@extension("VK_NVX_raytracing") // 166
-bitfield VkBuildAccelerationStructureFlagBitsNVX {
-    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NVX        = 0x00000001,
-    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NVX    = 0x00000002,
-    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NVX   = 0x00000004,
-    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NVX   = 0x00000008,
-    VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NVX          = 0x00000010,
+@extension("VK_NV_raytracing") // 166
+type VkFlags VkBuildAccelerationStructureFlagsNV
+@extension("VK_NV_raytracing") // 166
+bitfield VkBuildAccelerationStructureFlagBitsNV {
+    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV         = 0x00000001,
+    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV     = 0x00000002,
+    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV    = 0x00000004,
+    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV    = 0x00000008,
+    VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV           = 0x00000010,
 }
 
+@extension("VK_FUCHSIA_imagepipe_surface") // 215
+type VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA
+//@extension("VK_FUCHSIA_imagepipe_surface") // 215
+//bitfield VkImagePipeSurfaceCreateFlagBitsFUCHSIA {
+//}
+
 //////////////////
 //  Structures  //
 //////////////////
@@ -5237,15 +5351,6 @@
     platform.wl_surface*                        surface
 }
 
-@extension("VK_KHR_mir_surface") // 8
-class VkMirSurfaceCreateInfoKHR {
-    VkStructureType                             sType
-    const void*                                 pNext
-    VkMirSurfaceCreateFlagsKHR                  flags
-    platform.MirConnection*                     connection
-    platform.MirSurface*                        mirSurface
-}
-
 @extension("VK_KHR_android_surface") // 9
 class VkAndroidSurfaceCreateInfoKHR {
     VkStructureType                             sType
@@ -5360,6 +5465,38 @@
     VkBuffer                                    buffer
 }
 
+@extension("VK_EXT_transform_feedback") // 29
+class VkPhysicalDeviceTransformFeedbackFeaturesEXT {
+    VkStructureType                             sType
+    void*                                       pNext
+    VkBool32                                    transformFeedback
+    VkBool32                                    geometryStreams
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+class VkPhysicalDeviceTransformFeedbackPropertiesEXT {
+    VkStructureType                             sType
+    void*                                       pNext
+    u32                                         maxTransformFeedbackStreams
+    u32                                         maxTransformFeedbackBuffers
+    VkDeviceSize                                maxTransformFeedbackBufferSize
+    u32                                         maxTransformFeedbackStreamDataSize
+    u32                                         maxTransformFeedbackBufferDataSize
+    u32                                         maxTransformFeedbackBufferDataStride
+    VkBool32                                    transformFeedbackQueries
+    VkBool32                                    transformFeedbackStreamsLinesTriangles
+    VkBool32                                    transformFeedbackRasterizationStreamSelect
+    VkBool32                                    transformFeedbackDraw
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+class VkPipelineRasterizationStateStreamCreateInfoEXT {
+    VkStructureType                                     sType
+    const void*                                         pNext
+    VkPipelineRasterizationStateStreamCreateFlagsEXT    flags
+    u32                                                 rasterizationStream
+}
+
 @extension("VK_AMD_texture_gather_bias_lod") // 42
 class VkTextureLODGatherFormatPropertiesAMD {
     VkStructureType                             sType
@@ -6599,7 +6736,7 @@
     const void*                                     pNext
     VkDebugUtilsMessengerCreateFlagsEXT             flags
     VkDebugUtilsMessageSeverityFlagsEXT             messageSeverity
-    VkDebugUtilsMessageTypeFlagsEXT                 messageType
+    VkDebugUtilsMessageTypeFlagsEXT                 messageTypes
     PFN_vkDebugUtilsMessengerCallbackEXT            pfnUserCallback
     void*                                           pUserData
 }
@@ -6925,6 +7062,55 @@
     VkDeviceSize                                    memoryOffset
 }
 
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkDrmFormatModifierPropertiesEXT {
+    u64                                             drmFormatModifier
+    u32                                             drmFormatModifierPlaneCount
+    VkFormatFeatureFlags                            drmFormatModifierTilingFeatures
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkDrmFormatModifierPropertiesListEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u32                                             drmFormatModifierCount
+    VkDrmFormatModifierPropertiesEXT*               pDrmFormatModifierProperties
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkPhysicalDeviceImageDrmFormatModifierInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u64                                             drmFormatModifier
+    VkSharingMode                                   sharingMode
+    u32                                             queueFamilyIndexCount
+    const u32*                                      pQueueFamilyIndices
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkImageDrmFormatModifierListCreateInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u32                                             drmFormatModifierCount
+    const u64*                                      pDrmFormatModifiers
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkImageDrmFormatModifierExplicitCreateInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u64                                             drmFormatModifier
+    u32                                             drmFormatModifierPlaneCount
+    const VkSubresourceLayout*                      pPlaneLayouts
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkImageDrmFormatModifierPropertiesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u64                                             drmFormatModifier
+}
+
 @extension("VK_EXT_validation_cache") // 161
 class VkValidationCacheCreateInfoEXT {
     VkStructureType                                 sType
@@ -7075,22 +7261,34 @@
     const VkCoarseSampleOrderCustomNV*              pCustomSampleOrders
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkRaytracingPipelineCreateInfoNVX {
-    VkStructureType                                 sType
-    const void*                                     pNext
-    VkPipelineCreateFlags                           flags
-    u32                                             stageCount
-    const VkPipelineShaderStageCreateInfo*          pStages
-    const u32*                                      pGroupNumbers
-    u32                                             maxRecursionDepth
-    VkPipelineLayout                                layout
-    VkPipeline                                      basePipelineHandle
-    s32                                             basePipelineIndex
+@extension("VK_NV_raytracing") // 166
+class VkRayTracingShaderGroupCreateInfoNV {
+    VkStructureType                  sType
+    const void*                      pNext
+    VkRayTracingShaderGroupTypeNV    type
+    u32                              generalShader
+    u32                              closestHitShader
+    u32                              anyHitShader
+    u32                              intersectionShader
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkGeometryTrianglesNVX {
+@extension("VK_NV_raytracing") // 166
+class VkRayTracingPipelineCreateInfoNV {
+    VkStructureType                               sType
+    const void*                                   pNext
+    VkPipelineCreateFlags                         flags
+    u32                                           stageCount
+    const VkPipelineShaderStageCreateInfo*        pStages
+    u32                                           groupCount
+    const VkRayTracingShaderGroupCreateInfoNV*    pGroups
+    u32                                           maxRecursionDepth
+    VkPipelineLayout                              layout
+    VkPipeline                                    basePipelineHandle
+    s32                                           basePipelineIndex
+}
+
+@extension("VK_NV_raytracing") // 166
+class VkGeometryTrianglesNV {
     VkStructureType                                 sType
     const void*                                     pNext
     VkBuffer                                        vertexData
@@ -7106,8 +7304,8 @@
     VkDeviceSize                                    transformOffset
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkGeometryAABBNVX {
+@extension("VK_NV_raytracing") // 166
+class VkGeometryAABBNV {
     VkStructureType                                 sType
     const void*                                     pNext
     VkBuffer                                        aabbData
@@ -7116,66 +7314,79 @@
     VkDeviceSize                                    offset
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkGeometryDataNVX {
-    VkGeometryTrianglesNVX                          triangles
-    VkGeometryAABBNVX                               aabbs
+@extension("VK_NV_raytracing") // 166
+class VkGeometryDataNV {
+    VkGeometryTrianglesNV                           triangles
+    VkGeometryAABBNV                                aabbs
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkGeometryNVX {
+@extension("VK_NV_raytracing") // 166
+class VkGeometryNV {
     VkStructureType                                 sType
     const void*                                     pNext
-    VkGeometryTypeNVX                               geometryType
-    VkGeometryDataNVX                               geometry
-    VkGeometryFlagsNVX                              flags
+    VkGeometryTypeNV                                geometryType
+    VkGeometryDataNV                                geometry
+    VkGeometryFlagsNV                               flags
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkAccelerationStructureCreateInfoNVX {
+@extension("VK_NV_raytracing") // 166
+class VkAccelerationStructureInfoNV {
     VkStructureType                                 sType
     const void*                                     pNext
-    VkAccelerationStructureTypeNVX                  type
-    VkBuildAccelerationStructureFlagsNVX            flags
-    VkDeviceSize                                    compactedSize
+    VkAccelerationStructureTypeNV                   type
+    VkBuildAccelerationStructureFlagsNV             flags
     u32                                             instanceCount
     u32                                             geometryCount
-    const VkGeometryNVX*                            pGeometries
+    const VkGeometryNV*                             pGeometries
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkBindAccelerationStructureMemoryInfoNVX {
+@extension("VK_NV_raytracing") // 166
+class VkAccelerationStructureCreateInfoNV {
     VkStructureType                                 sType
     const void*                                     pNext
-    VkAccelerationStructureNVX                      accelerationStructure
+    VkDeviceSize                                    compactedSize
+    VkAccelerationStructureInfoNV                   info
+}
+
+@extension("VK_NV_raytracing") // 166
+class VkBindAccelerationStructureMemoryInfoNV {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkAccelerationStructureNV                       accelerationStructure
     VkDeviceMemory                                  memory
     VkDeviceSize                                    memoryOffset
     u32                                             deviceIndexCount
     const u32*                                      pDeviceIndices
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkDescriptorAccelerationStructureInfoNVX {
+@extension("VK_NV_raytracing") // 166
+class VkDescriptorAccelerationStructureInfoNV {
     VkStructureType                                 sType
     const void*                                     pNext
     u32                                             accelerationStructureCount
-    const VkAccelerationStructureNVX*               pAccelerationStructures
+    const VkAccelerationStructureNV*                pAccelerationStructures
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkAccelerationStructureMemoryRequirementsInfoNVX {
+@extension("VK_NV_raytracing") // 166
+class VkAccelerationStructureMemoryRequirementsInfoNV {
     VkStructureType                                 sType
     const void*                                     pNext
-    VkAccelerationStructureNVX                      accelerationStructure
+    VkAccelerationStructureMemoryRequirementsTypeNV type
+    VkAccelerationStructureNV                       accelerationStructure
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkPhysicalDeviceRaytracingPropertiesNVX {
+@extension("VK_NV_raytracing") // 166
+class VkPhysicalDeviceRaytracingPropertiesNV {
     VkStructureType                                 sType
     void*                                           pNext
-    u32                                             shaderHeaderSize
+    u32                                             shaderGroupHandleSize
     u32                                             maxRecursionDepth
-    u32                                             maxGeometryCount
+    u32                                             maxShaderGroupStride
+    u32                                             shaderGroupBaseAlignment
+    u64                                             maxGeometryCount
+    u64                                             maxInstanceCount
+    u64                                             maxTriangleCount
+    u32                                             maxDescriptorSetAccelerationStructures
 }
 
 @extension("VK_NV_representative_fragment_test") // 167
@@ -7253,6 +7464,13 @@
     VkBool32                                        shaderSharedInt64Atomics
 }
 
+@extension("VK_EXT_calibrated_timestamps") // 185
+class VkCalibratedTimestampInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkTimeDomainEXT                                 timeDomain
+}
+
 @extension("VK_AMD_shader_core_properties") // 186
 class VkPhysicalDeviceShaderCorePropertiesAMD {
     VkStructureType                                 sType
@@ -7273,6 +7491,13 @@
     u32                                             vgprAllocationGranularity
 }
 
+@extension("VK_AMD_memory_overallocation_behavior") // 190
+class VkDeviceMemoryOverallocationCreateInfoAMD {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkMemoryOverallocationBehaviorAMD               overallocationBehavior
+}
+
 @extension("VK_EXT_vertex_attribute_divisor") // 191
 class VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT {
     VkStructureType                                 sType
@@ -7314,7 +7539,7 @@
 class VkPhysicalDeviceDriverPropertiesKHR {
     VkStructureType                                 sType
     void*                                           pNext
-    u32                                             driverID
+    VkDriverIdKHR                                   driverID
     char[VK_MAX_DRIVER_NAME_SIZE_KHR]               driverName
     char[VK_MAX_DRIVER_INFO_SIZE_KHR]               driverInfo
     VkConformanceVersionKHR                         conformanceVersion
@@ -7413,6 +7638,24 @@
     VkBool32                                        vulkanMemoryModelDeviceScope
 }
 
+@extension("VK_EXT_pci_bus_info") // 213
+class VkPhysicalDevicePCIBusInfoPropertiesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u16                                             pciDomain
+    u8                                              pciBus
+    u8                                              pciDevice
+    u8                                              pciFunction
+}
+
+@extension("VK_FUCHSIA_imagepipe_surface") // 215
+class VkImagePipeSurfaceCreateInfoFUCHSIA {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkImagePipeSurfaceCreateFlagsFUCHSIA            flags
+    platform.zx_handle_t                            imagePipeHandle
+}
+
 
 ////////////////
 //  Commands  //
@@ -10171,25 +10414,6 @@
     return ?
 }
 
-@extension("VK_KHR_mir_surface") // 8
-cmd VkResult vkCreateMirSurfaceKHR(
-        VkInstance                              instance,
-        const VkMirSurfaceCreateInfoKHR*        pCreateInfo,
-        const VkAllocationCallbacks*            pAllocator,
-        VkSurfaceKHR*                           pSurface) {
-    instanceObject := GetInstance(instance)
-    return ?
-}
-
-@extension("VK_KHR_mir_surface") // 8
-cmd VkBool32 vkGetPhysicalDeviceMirPresentationSupportKHR(
-        VkPhysicalDevice                        physicalDevice,
-        u32                                     queueFamilyIndex,
-        platform.MirConnection*                 connection) {
-    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-    return ?
-}
-
 @extension("VK_KHR_android_surface") // 9
 cmd VkResult vkCreateAndroidSurfaceKHR(
         VkInstance                              instance,
@@ -10334,6 +10558,62 @@
         const VkDebugMarkerMarkerInfoEXT*           pMarkerInfo) {
 }
 
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdBindTransformFeedbackBuffersEXT(
+        VkCommandBuffer                             commandBuffer,
+        u32                                         firstBinding,
+        u32                                         bindingCount,
+        const VkBuffer*                             pBuffers,
+        const VkDeviceSize*                         pOffsets,
+        const VkDeviceSize*                         pSizes) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdBeginTransformFeedbackEXT(
+        VkCommandBuffer                             commandBuffer,
+        u32                                         firstCounterBuffer,
+        u32                                         counterBufferCount,
+        const VkBuffer*                             pCounterBuffers,
+        const VkDeviceSize*                         pCounterBufferOffsets) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdEndTransformFeedbackEXT(
+        VkCommandBuffer                             commandBuffer,
+        u32                                         firstCounterBuffer,
+        u32                                         counterBufferCount,
+        const VkBuffer*                             pCounterBuffers,
+        const VkDeviceSize*                         pCounterBufferOffsets) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdBeginQueryIndexedEXT(
+        VkCommandBuffer                             commandBuffer,
+        VkQueryPool                                 queryPool,
+        u32                                         query,
+        VkQueryControlFlags                         flags,
+        u32                                         index) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdEndQueryIndexedEXT(
+        VkCommandBuffer                             commandBuffer,
+        VkQueryPool                                 queryPool,
+        u32                                         query,
+        u32                                         index) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdDrawIndirectByteCountEXT(
+        VkCommandBuffer                             commandBuffer,
+        u32                                         instanceCount,
+        u32                                         firstInstance,
+        VkBuffer                                    counterBuffer,
+        VkDeviceSize                                counterBufferOffset,
+        u32                                         counterOffset,
+        u32                                         vertexStride) {
+}
+
 @extension("VK_AMD_draw_indirect_count") // 34
 cmd void vkCmdDrawIndirectCountAMD(
         VkCommandBuffer                             commandBuffer,
@@ -11128,6 +11408,14 @@
     return ?
 }
 
+@extension("VK_EXT_image_drm_format_modifier") // 159
+cmd VkResult vkGetImageDrmFormatModifierPropertiesEXT(
+        VkDevice                                        device,
+        VkImage                                         image,
+        VkImageDrmFormatModifierPropertiesEXT*          pProperties) {
+    return ?
+}
+
 @extension("VK_EXT_validation_cache") // 161
 cmd VkResult vkCreateValidationCacheEXT(
         VkDevice                                    device,
@@ -11185,71 +11473,60 @@
         const VkCoarseSampleOrderCustomNV*          pCustomSampleOrders) {
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkCreateAccelerationStructureNVX(
+@extension("VK_NV_raytracing") // 166
+cmd VkResult vkCreateAccelerationStructureNV(
         VkDevice                                    device,
-        const VkAccelerationStructureCreateInfoNVX* pCreateInfo,
+        const VkAccelerationStructureCreateInfoNV*  pCreateInfo,
         const VkAllocationCallbacks*                pAllocator,
-        VkAccelerationStructureNVX*                 pAccelerationStructure) {
+        VkAccelerationStructureNV*                  pAccelerationStructure) {
     return ?
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd void vkDestroyAccelerationStructureNVX(
+@extension("VK_NV_raytracing") // 166
+cmd void vkDestroyAccelerationStructureNV(
         VkDevice                                    device,
-        VkAccelerationStructureNVX                  accelerationStructure,
+        VkAccelerationStructureNV                   accelerationStructure,
         const VkAllocationCallbacks*                pAllocator) {
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd void vkGetAccelerationStructureMemoryRequirementsNVX(
+@extension("VK_NV_raytracing") // 166
+cmd void vkGetAccelerationStructureMemoryRequirementsNV(
         VkDevice                                                device,
-        const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo,
+        const VkAccelerationStructureMemoryRequirementsInfoNV*  pInfo,
         VkMemoryRequirements2KHR*                               pMemoryRequirements) {
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd void vkGetAccelerationStructureScratchMemoryRequirementsNVX(
-        VkDevice                                                device,
-        const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo,
-        VkMemoryRequirements2KHR*                               pMemoryRequirements) {
-}
-
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkBindAccelerationStructureMemoryNVX(
+@extension("VK_NV_raytracing") // 166
+cmd VkResult vkBindAccelerationStructureMemoryNV(
         VkDevice                                        device,
         u32                                             bindInfoCount,
-        const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos) {
+        const VkBindAccelerationStructureMemoryInfoNV*  pBindInfos) {
     return ?
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd void vkCmdBuildAccelerationStructureNVX(
+@extension("VK_NV_raytracing") // 166
+cmd void vkCmdBuildAccelerationStructureNV(
         VkCommandBuffer                             commandBuffer,
-        VkAccelerationStructureTypeNVX              type,
-        u32                                         instanceCount,
+        const VkAccelerationStructureInfoNV*        pInfo,
         VkBuffer                                    instanceData,
         VkDeviceSize                                instanceOffset,
-        u32                                         geometryCount,
-        const VkGeometryNVX*                        pGeometries,
-        VkBuildAccelerationStructureFlagsNVX        flags,
         VkBool32                                    update,
-        VkAccelerationStructureNVX                  dst,
-        VkAccelerationStructureNVX                  src,
+        VkAccelerationStructureNV                   dst,
+        VkAccelerationStructureNV                   src,
         VkBuffer                                    scratch,
         VkDeviceSize                                scratchOffset) {
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd void vkCmdCopyAccelerationStructureNVX(
+@extension("VK_NV_raytracing") // 166
+cmd void vkCmdCopyAccelerationStructureNV(
         VkCommandBuffer                             commandBuffer,
-        VkAccelerationStructureNVX                  dst,
-        VkAccelerationStructureNVX                  src,
-        VkCopyAccelerationStructureModeNVX          mode) {
+        VkAccelerationStructureNV                   dst,
+        VkAccelerationStructureNV                   src,
+        VkCopyAccelerationStructureModeNV           mode) {
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd void vkCmdTraceRaysNVX(
+@extension("VK_NV_raytracing") // 166
+cmd void vkCmdTraceRaysNV(
         VkCommandBuffer                             commandBuffer,
         VkBuffer                                    raygenShaderBindingTableBuffer,
         VkDeviceSize                                raygenShaderBindingOffset,
@@ -11259,23 +11536,27 @@
         VkBuffer                                    hitShaderBindingTableBuffer,
         VkDeviceSize                                hitShaderBindingOffset,
         VkDeviceSize                                hitShaderBindingStride,
+        VkBuffer                                    callableShaderBindingTableBuffer,
+        VkDeviceSize                                callableShaderBindingOffset,
+        VkDeviceSize                                callableShaderBindingStride,
         u32                                         width,
-        u32                                         height) {
+        u32                                         height,
+        u32                                         depth) {
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkCreateRaytracingPipelinesNVX(
+@extension("VK_NV_raytracing") // 166
+cmd VkResult vkCreateRaytracingPipelinesNV(
         VkDevice                                    device,
         VkPipelineCache                             pipelineCache,
         u32                                         createInfoCount,
-        const VkRaytracingPipelineCreateInfoNVX*    pCreateInfos,
+        const VkRayTracingPipelineCreateInfoNV*     pCreateInfos,
         const VkAllocationCallbacks*                pAllocator,
         VkPipeline*                                 pPipelines) {
     return ?
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkGetRaytracingShaderHandlesNVX(
+@extension("VK_NV_raytracing") // 166
+cmd VkResult vkGetRaytracingShaderHandlesNV(
         VkDevice                                    device,
         VkPipeline                                  pipeline,
         u32                                         firstGroup,
@@ -11285,26 +11566,27 @@
     return ?
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkGetAccelerationStructureHandleNVX(
+@extension("VK_NV_raytracing") // 166
+cmd VkResult vkGetAccelerationStructureHandleNV(
         VkDevice                                    device,
-        VkAccelerationStructureNVX                  accelerationStructure,
+        VkAccelerationStructureNV                   accelerationStructure,
         platform.size_t                             dataSize,
         void*                                       pData) {
     return ?
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd void vkCmdWriteAccelerationStructurePropertiesNVX(
+@extension("VK_NV_raytracing") // 166
+cmd void vkCmdWriteAccelerationStructurePropertiesNV(
         VkCommandBuffer                             commandBuffer,
-        VkAccelerationStructureNVX                  accelerationStructure,
+        u32                                         accelerationStructureCount,
+        const VkAccelerationStructureNV*            pAccelerationStructures,
         VkQueryType                                 queryType,
         VkQueryPool                                 queryPool,
-        u32                                         query) {
+        u32                                         firstQuery) {
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkCompileDeferredNVX(
+@extension("VK_NV_raytracing") // 166
+cmd VkResult vkCompileDeferredNV(
         VkDevice                                    device,
         VkPipeline                                  pipeline,
         u32                                         shader) {
@@ -11358,6 +11640,24 @@
         u32                                         marker) {
 }
 
+@extension("VK_EXT_calibrated_timestamps") // 185
+cmd VkResult vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(
+        VkPhysicalDevice                            physicalDevice,
+        u32*                                        pTimeDomainCount,
+        VkTimeDomainEXT*                            pTimeDomains) {
+    return ?
+}
+
+@extension("VK_EXT_calibrated_timestamps") // 185
+cmd VkResult vkGetCalibratedTimestampsEXT(
+        VkDevice                                    device,
+        u32                                         timestampCount,
+        const VkCalibratedTimestampInfoEXT*         pTimestampInfos,
+        u64*                                        pTimestamps,
+        u64*                                        pMaxDeviation) {
+    return ?
+}
+
 @extension("VK_NV_mesh_shader") // 203
 cmd void vkCmdDrawMeshTasksNV(
         VkCommandBuffer                             commandBuffer,
@@ -11406,6 +11706,15 @@
         VkCheckpointDataNV*                         pCheckpointData) {
 }
 
+@extension("VK_FUCHSIA_imagepipe_surface") // 215
+cmd VkResult vkCreateImagePipeSurfaceFUCHSIA(
+        VkInstance                                  instance,
+        const VkImagePipeSurfaceCreateInfoFUCHSIA*  pCreateInfo,
+        const VkAllocationCallbacks*                pAllocator,
+        VkSurfaceKHR*                               pSurface) {
+    return ?
+}
+
 
 ////////////////
 // Validation //
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index d05c849..77da637 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -24,6 +24,10 @@
 #include "vulkan_android.h"
 #endif
 
+#ifdef VK_USE_PLATFORM_FUCHSIA
+#include <zircon/types.h>
+#include "vulkan_fuchsia.h"
+#endif
 
 #ifdef VK_USE_PLATFORM_IOS_MVK
 #include "vulkan_ios.h"
@@ -35,12 +39,6 @@
 #endif
 
 
-#ifdef VK_USE_PLATFORM_MIR_KHR
-#include <mir_toolkit/client_types.h>
-#include "vulkan_mir.h"
-#endif
-
-
 #ifdef VK_USE_PLATFORM_VI_NN
 #include "vulkan_vi.h"
 #endif
diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h
index 39f4dc6..4cd8ed5 100644
--- a/vulkan/include/vulkan/vulkan_core.h
+++ b/vulkan/include/vulkan/vulkan_core.h
@@ -43,11 +43,10 @@
 #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
 #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 // Version of this file
-#define VK_HEADER_VERSION 86
+#define VK_HEADER_VERSION 91
 
 
 #define VK_NULL_HANDLE 0
-        
 
 
 #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
@@ -60,7 +59,6 @@
         #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
 #endif
 #endif
-        
 
 
 typedef uint32_t VkFlags;
@@ -147,6 +145,7 @@
     VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
     VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
     VK_ERROR_INVALID_SHADER_NV = -1000012000,
+    VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000,
     VK_ERROR_FRAGMENTATION_EXT = -1000161000,
     VK_ERROR_NOT_PERMITTED_EXT = -1000174001,
     VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY,
@@ -286,7 +285,6 @@
     VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
     VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
     VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
-    VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
     VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000,
     VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
     VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000,
@@ -297,6 +295,9 @@
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001,
+    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002,
     VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000,
     VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
@@ -398,6 +399,12 @@
     VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002,
     VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000,
     VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000,
+    VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000,
+    VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002,
+    VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003,
+    VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004,
+    VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005,
     VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000,
     VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001,
     VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = 1000161000,
@@ -409,17 +416,17 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002,
     VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005,
-    VK_STRUCTURE_TYPE_RAYTRACING_PIPELINE_CREATE_INFO_NVX = 1000165000,
-    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NVX = 1000165001,
-    VK_STRUCTURE_TYPE_GEOMETRY_INSTANCE_NVX = 1000165002,
-    VK_STRUCTURE_TYPE_GEOMETRY_NVX = 1000165003,
-    VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NVX = 1000165004,
-    VK_STRUCTURE_TYPE_GEOMETRY_AABB_NVX = 1000165005,
-    VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NVX = 1000165006,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_ACCELERATION_STRUCTURE_INFO_NVX = 1000165007,
-    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NVX = 1000165008,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAYTRACING_PROPERTIES_NVX = 1000165009,
-    VK_STRUCTURE_TYPE_HIT_SHADER_MODULE_CREATE_INFO_NVX = 1000165010,
+    VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000,
+    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001,
+    VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003,
+    VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004,
+    VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005,
+    VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006,
+    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007,
+    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009,
+    VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011,
+    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000,
     VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001,
     VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000,
@@ -428,7 +435,9 @@
     VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000,
+    VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
+    VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000,
     VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002,
@@ -443,6 +452,8 @@
     VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000,
     VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000,
+    VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000,
     VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
     VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES,
@@ -811,6 +822,7 @@
 typedef enum VkImageTiling {
     VK_IMAGE_TILING_OPTIMAL = 0,
     VK_IMAGE_TILING_LINEAR = 1,
+    VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000,
     VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL,
     VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR,
     VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1),
@@ -833,7 +845,8 @@
     VK_QUERY_TYPE_OCCLUSION = 0,
     VK_QUERY_TYPE_PIPELINE_STATISTICS = 1,
     VK_QUERY_TYPE_TIMESTAMP = 2,
-    VK_QUERY_TYPE_COMPACTED_SIZE_NVX = 1000165000,
+    VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004,
+    VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000,
     VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION,
     VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP,
     VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1),
@@ -1163,7 +1176,7 @@
     VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9,
     VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10,
     VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000,
-    VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NVX = 1000165000,
+    VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
     VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER,
     VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
     VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1),
@@ -1192,7 +1205,7 @@
 typedef enum VkPipelineBindPoint {
     VK_PIPELINE_BIND_POINT_GRAPHICS = 0,
     VK_PIPELINE_BIND_POINT_COMPUTE = 1,
-    VK_PIPELINE_BIND_POINT_RAYTRACING_NVX = 1000165000,
+    VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = 1000165000,
     VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS,
     VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE,
     VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1),
@@ -1211,6 +1224,7 @@
 typedef enum VkIndexType {
     VK_INDEX_TYPE_UINT16 = 0,
     VK_INDEX_TYPE_UINT32 = 1,
+    VK_INDEX_TYPE_NONE_NV = 1000165000,
     VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16,
     VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32,
     VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1),
@@ -1264,7 +1278,7 @@
     VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,
     VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000,
     VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000,
-    VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX = 1000165000,
+    VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
     VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE,
     VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION,
     VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN,
@@ -1428,10 +1442,12 @@
     VK_PIPELINE_STAGE_HOST_BIT = 0x00004000,
     VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000,
     VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000,
+    VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000,
     VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000,
     VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000,
     VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000,
-    VK_PIPELINE_STAGE_RAYTRACING_BIT_NVX = 0x00200000,
+    VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = 0x00200000,
+    VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000,
     VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000,
     VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000,
     VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
@@ -1447,6 +1463,10 @@
     VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010,
     VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020,
     VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400,
     VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT,
     VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT,
     VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT,
@@ -1521,8 +1541,10 @@
     VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040,
     VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080,
     VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100,
+    VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800,
+    VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000,
     VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200,
-    VK_BUFFER_USAGE_RAYTRACING_BIT_NVX = 0x00000400,
+    VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = 0x00000400,
     VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkBufferUsageFlagBits;
 typedef VkFlags VkBufferUsageFlags;
@@ -1537,7 +1559,7 @@
     VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004,
     VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008,
     VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010,
-    VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NVX = 0x00000020,
+    VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020,
     VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT,
     VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE,
     VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
@@ -1554,12 +1576,12 @@
     VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020,
     VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F,
     VK_SHADER_STAGE_ALL = 0x7FFFFFFF,
-    VK_SHADER_STAGE_RAYGEN_BIT_NVX = 0x00000100,
-    VK_SHADER_STAGE_ANY_HIT_BIT_NVX = 0x00000200,
-    VK_SHADER_STAGE_CLOSEST_HIT_BIT_NVX = 0x00000400,
-    VK_SHADER_STAGE_MISS_BIT_NVX = 0x00000800,
-    VK_SHADER_STAGE_INTERSECTION_BIT_NVX = 0x00001000,
-    VK_SHADER_STAGE_CALLABLE_BIT_NVX = 0x00002000,
+    VK_SHADER_STAGE_RAYGEN_BIT_NV = 0x00000100,
+    VK_SHADER_STAGE_ANY_HIT_BIT_NV = 0x00000200,
+    VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = 0x00000400,
+    VK_SHADER_STAGE_MISS_BIT_NV = 0x00000800,
+    VK_SHADER_STAGE_INTERSECTION_BIT_NV = 0x00001000,
+    VK_SHADER_STAGE_CALLABLE_BIT_NV = 0x00002000,
     VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040,
     VK_SHADER_STAGE_MESH_BIT_NV = 0x00000080,
     VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
@@ -1643,13 +1665,16 @@
     VK_ACCESS_HOST_WRITE_BIT = 0x00004000,
     VK_ACCESS_MEMORY_READ_BIT = 0x00008000,
     VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,
+    VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000,
+    VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000,
+    VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000,
     VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000,
     VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,
     VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,
     VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000,
     VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000,
-    VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NVX = 0x00200000,
-    VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVX = 0x00400000,
+    VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000,
+    VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000,
     VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkAccessFlagBits;
 typedef VkFlags VkAccessFlags;
@@ -6092,7 +6117,7 @@
 typedef struct VkPhysicalDeviceDriverPropertiesKHR {
     VkStructureType            sType;
     void*                      pNext;
-    uint32_t                   driverID;
+    VkDriverIdKHR              driverID;
     char                       driverName[VK_MAX_DRIVER_NAME_SIZE_KHR];
     char                       driverInfo[VK_MAX_DRIVER_INFO_SIZE_KHR];
     VkConformanceVersionKHR    conformanceVersion;
@@ -6157,7 +6182,7 @@
     VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33,
     VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000,
     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000,
-    VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX_EXT = 1000165000,
+    VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000,
     VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT,
     VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT,
     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT,
@@ -6359,6 +6384,95 @@
 
 
 
+#define VK_EXT_transform_feedback 1
+#define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1
+#define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback"
+
+typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT;
+
+typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           transformFeedback;
+    VkBool32           geometryStreams;
+} VkPhysicalDeviceTransformFeedbackFeaturesEXT;
+
+typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           maxTransformFeedbackStreams;
+    uint32_t           maxTransformFeedbackBuffers;
+    VkDeviceSize       maxTransformFeedbackBufferSize;
+    uint32_t           maxTransformFeedbackStreamDataSize;
+    uint32_t           maxTransformFeedbackBufferDataSize;
+    uint32_t           maxTransformFeedbackBufferDataStride;
+    VkBool32           transformFeedbackQueries;
+    VkBool32           transformFeedbackStreamsLinesTriangles;
+    VkBool32           transformFeedbackRasterizationStreamSelect;
+    VkBool32           transformFeedbackDraw;
+} VkPhysicalDeviceTransformFeedbackPropertiesEXT;
+
+typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT {
+    VkStructureType                                     sType;
+    const void*                                         pNext;
+    VkPipelineRasterizationStateStreamCreateFlagsEXT    flags;
+    uint32_t                                            rasterizationStream;
+} VkPipelineRasterizationStateStreamCreateInfoEXT;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes);
+typedef void (VKAPI_PTR *PFN_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets);
+typedef void (VKAPI_PTR *PFN_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets);
+typedef void (VKAPI_PTR *PFN_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index);
+typedef void (VKAPI_PTR *PFN_vkCmdEndQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index);
+typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdBindTransformFeedbackBuffersEXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    firstBinding,
+    uint32_t                                    bindingCount,
+    const VkBuffer*                             pBuffers,
+    const VkDeviceSize*                         pOffsets,
+    const VkDeviceSize*                         pSizes);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBeginTransformFeedbackEXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    firstCounterBuffer,
+    uint32_t                                    counterBufferCount,
+    const VkBuffer*                             pCounterBuffers,
+    const VkDeviceSize*                         pCounterBufferOffsets);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdEndTransformFeedbackEXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    firstCounterBuffer,
+    uint32_t                                    counterBufferCount,
+    const VkBuffer*                             pCounterBuffers,
+    const VkDeviceSize*                         pCounterBufferOffsets);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBeginQueryIndexedEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    query,
+    VkQueryControlFlags                         flags,
+    uint32_t                                    index);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdEndQueryIndexedEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    query,
+    uint32_t                                    index);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectByteCountEXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    instanceCount,
+    uint32_t                                    firstInstance,
+    VkBuffer                                    counterBuffer,
+    VkDeviceSize                                counterBufferOffset,
+    uint32_t                                    counterOffset,
+    uint32_t                                    vertexStride);
+#endif
+
 #define VK_AMD_draw_indirect_count 1
 #define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
 #define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
@@ -7341,7 +7455,7 @@
 
 typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)(
     VkDebugUtilsMessageSeverityFlagBitsEXT           messageSeverity,
-    VkDebugUtilsMessageTypeFlagsEXT                  messageType,
+    VkDebugUtilsMessageTypeFlagsEXT                  messageTypes,
     const VkDebugUtilsMessengerCallbackDataEXT*      pCallbackData,
     void*                                            pUserData);
 
@@ -7676,6 +7790,65 @@
 #define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage"
 
 
+#define VK_EXT_image_drm_format_modifier 1
+#define VK_EXT_EXTENSION_159_SPEC_VERSION 0
+#define VK_EXT_EXTENSION_159_EXTENSION_NAME "VK_EXT_extension_159"
+#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1
+#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier"
+
+typedef struct VkDrmFormatModifierPropertiesEXT {
+    uint64_t                drmFormatModifier;
+    uint32_t                drmFormatModifierPlaneCount;
+    VkFormatFeatureFlags    drmFormatModifierTilingFeatures;
+} VkDrmFormatModifierPropertiesEXT;
+
+typedef struct VkDrmFormatModifierPropertiesListEXT {
+    VkStructureType                      sType;
+    void*                                pNext;
+    uint32_t                             drmFormatModifierCount;
+    VkDrmFormatModifierPropertiesEXT*    pDrmFormatModifierProperties;
+} VkDrmFormatModifierPropertiesListEXT;
+
+typedef struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint64_t           drmFormatModifier;
+    VkSharingMode      sharingMode;
+    uint32_t           queueFamilyIndexCount;
+    const uint32_t*    pQueueFamilyIndices;
+} VkPhysicalDeviceImageDrmFormatModifierInfoEXT;
+
+typedef struct VkImageDrmFormatModifierListCreateInfoEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           drmFormatModifierCount;
+    const uint64_t*    pDrmFormatModifiers;
+} VkImageDrmFormatModifierListCreateInfoEXT;
+
+typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT {
+    VkStructureType               sType;
+    const void*                   pNext;
+    uint64_t                      drmFormatModifier;
+    uint32_t                      drmFormatModifierPlaneCount;
+    const VkSubresourceLayout*    pPlaneLayouts;
+} VkImageDrmFormatModifierExplicitCreateInfoEXT;
+
+typedef struct VkImageDrmFormatModifierPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint64_t           drmFormatModifier;
+} VkImageDrmFormatModifierPropertiesEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetImageDrmFormatModifierPropertiesEXT)(VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetImageDrmFormatModifierPropertiesEXT(
+    VkDevice                                    device,
+    VkImage                                     image,
+    VkImageDrmFormatModifierPropertiesEXT*      pProperties);
+#endif
+
 #define VK_EXT_validation_cache 1
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT)
 
@@ -7940,81 +8113,113 @@
     const VkCoarseSampleOrderCustomNV*          pCustomSampleOrders);
 #endif
 
-#define VK_NVX_raytracing 1
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNVX)
+#define VK_NV_ray_tracing 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV)
 
-#define VK_NVX_RAYTRACING_SPEC_VERSION    1
-#define VK_NVX_RAYTRACING_EXTENSION_NAME  "VK_NVX_raytracing"
+#define VK_NV_RAY_TRACING_SPEC_VERSION    2
+#define VK_NV_RAY_TRACING_EXTENSION_NAME  "VK_NV_ray_tracing"
+#define VK_SHADER_UNUSED_NV               (~0U)
 
 
-typedef enum VkGeometryTypeNVX {
-    VK_GEOMETRY_TYPE_TRIANGLES_NVX = 0,
-    VK_GEOMETRY_TYPE_AABBS_NVX = 1,
-    VK_GEOMETRY_TYPE_BEGIN_RANGE_NVX = VK_GEOMETRY_TYPE_TRIANGLES_NVX,
-    VK_GEOMETRY_TYPE_END_RANGE_NVX = VK_GEOMETRY_TYPE_AABBS_NVX,
-    VK_GEOMETRY_TYPE_RANGE_SIZE_NVX = (VK_GEOMETRY_TYPE_AABBS_NVX - VK_GEOMETRY_TYPE_TRIANGLES_NVX + 1),
-    VK_GEOMETRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkGeometryTypeNVX;
+typedef enum VkRayTracingShaderGroupTypeNV {
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = 0,
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = 1,
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = 2,
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_BEGIN_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV,
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_END_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV,
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_RANGE_SIZE_NV = (VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV - VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV + 1),
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkRayTracingShaderGroupTypeNV;
 
-typedef enum VkAccelerationStructureTypeNVX {
-    VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX = 0,
-    VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX = 1,
-    VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NVX = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX,
-    VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NVX = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX,
-    VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NVX = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX + 1),
-    VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkAccelerationStructureTypeNVX;
+typedef enum VkGeometryTypeNV {
+    VK_GEOMETRY_TYPE_TRIANGLES_NV = 0,
+    VK_GEOMETRY_TYPE_AABBS_NV = 1,
+    VK_GEOMETRY_TYPE_BEGIN_RANGE_NV = VK_GEOMETRY_TYPE_TRIANGLES_NV,
+    VK_GEOMETRY_TYPE_END_RANGE_NV = VK_GEOMETRY_TYPE_AABBS_NV,
+    VK_GEOMETRY_TYPE_RANGE_SIZE_NV = (VK_GEOMETRY_TYPE_AABBS_NV - VK_GEOMETRY_TYPE_TRIANGLES_NV + 1),
+    VK_GEOMETRY_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkGeometryTypeNV;
 
-typedef enum VkCopyAccelerationStructureModeNVX {
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX = 0,
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX = 1,
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_BEGIN_RANGE_NVX = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX,
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_END_RANGE_NVX = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX,
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_RANGE_SIZE_NVX = (VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX + 1),
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkCopyAccelerationStructureModeNVX;
+typedef enum VkAccelerationStructureTypeNV {
+    VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0,
+    VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1,
+    VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV,
+    VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV,
+    VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV + 1),
+    VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkAccelerationStructureTypeNV;
+
+typedef enum VkCopyAccelerationStructureModeNV {
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = 0,
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = 1,
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_BEGIN_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV,
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_END_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV,
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_RANGE_SIZE_NV = (VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV + 1),
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkCopyAccelerationStructureModeNV;
+
+typedef enum VkAccelerationStructureMemoryRequirementsTypeNV {
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV + 1),
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkAccelerationStructureMemoryRequirementsTypeNV;
 
 
-typedef enum VkGeometryFlagBitsNVX {
-    VK_GEOMETRY_OPAQUE_BIT_NVX = 0x00000001,
-    VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NVX = 0x00000002,
-    VK_GEOMETRY_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkGeometryFlagBitsNVX;
-typedef VkFlags VkGeometryFlagsNVX;
+typedef enum VkGeometryFlagBitsNV {
+    VK_GEOMETRY_OPAQUE_BIT_NV = 0x00000001,
+    VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = 0x00000002,
+    VK_GEOMETRY_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkGeometryFlagBitsNV;
+typedef VkFlags VkGeometryFlagsNV;
 
-typedef enum VkGeometryInstanceFlagBitsNVX {
-    VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NVX = 0x00000001,
-    VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_FLIP_WINDING_BIT_NVX = 0x00000002,
-    VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NVX = 0x00000004,
-    VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NVX = 0x00000008,
-    VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkGeometryInstanceFlagBitsNVX;
-typedef VkFlags VkGeometryInstanceFlagsNVX;
+typedef enum VkGeometryInstanceFlagBitsNV {
+    VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = 0x00000001,
+    VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002,
+    VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = 0x00000004,
+    VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = 0x00000008,
+    VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkGeometryInstanceFlagBitsNV;
+typedef VkFlags VkGeometryInstanceFlagsNV;
 
-typedef enum VkBuildAccelerationStructureFlagBitsNVX {
-    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NVX = 0x00000001,
-    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NVX = 0x00000002,
-    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NVX = 0x00000004,
-    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NVX = 0x00000008,
-    VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NVX = 0x00000010,
-    VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkBuildAccelerationStructureFlagBitsNVX;
-typedef VkFlags VkBuildAccelerationStructureFlagsNVX;
+typedef enum VkBuildAccelerationStructureFlagBitsNV {
+    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = 0x00000001,
+    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = 0x00000002,
+    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = 0x00000004,
+    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = 0x00000008,
+    VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = 0x00000010,
+    VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkBuildAccelerationStructureFlagBitsNV;
+typedef VkFlags VkBuildAccelerationStructureFlagsNV;
 
-typedef struct VkRaytracingPipelineCreateInfoNVX {
-    VkStructureType                           sType;
-    const void*                               pNext;
-    VkPipelineCreateFlags                     flags;
-    uint32_t                                  stageCount;
-    const VkPipelineShaderStageCreateInfo*    pStages;
-    const uint32_t*                           pGroupNumbers;
-    uint32_t                                  maxRecursionDepth;
-    VkPipelineLayout                          layout;
-    VkPipeline                                basePipelineHandle;
-    int32_t                                   basePipelineIndex;
-} VkRaytracingPipelineCreateInfoNVX;
+typedef struct VkRayTracingShaderGroupCreateInfoNV {
+    VkStructureType                  sType;
+    const void*                      pNext;
+    VkRayTracingShaderGroupTypeNV    type;
+    uint32_t                         generalShader;
+    uint32_t                         closestHitShader;
+    uint32_t                         anyHitShader;
+    uint32_t                         intersectionShader;
+} VkRayTracingShaderGroupCreateInfoNV;
 
-typedef struct VkGeometryTrianglesNVX {
+typedef struct VkRayTracingPipelineCreateInfoNV {
+    VkStructureType                               sType;
+    const void*                                   pNext;
+    VkPipelineCreateFlags                         flags;
+    uint32_t                                      stageCount;
+    const VkPipelineShaderStageCreateInfo*        pStages;
+    uint32_t                                      groupCount;
+    const VkRayTracingShaderGroupCreateInfoNV*    pGroups;
+    uint32_t                                      maxRecursionDepth;
+    VkPipelineLayout                              layout;
+    VkPipeline                                    basePipelineHandle;
+    int32_t                                       basePipelineIndex;
+} VkRayTracingPipelineCreateInfoNV;
+
+typedef struct VkGeometryTrianglesNV {
     VkStructureType    sType;
     const void*        pNext;
     VkBuffer           vertexData;
@@ -8028,136 +8233,138 @@
     VkIndexType        indexType;
     VkBuffer           transformData;
     VkDeviceSize       transformOffset;
-} VkGeometryTrianglesNVX;
+} VkGeometryTrianglesNV;
 
-typedef struct VkGeometryAABBNVX {
+typedef struct VkGeometryAABBNV {
     VkStructureType    sType;
     const void*        pNext;
     VkBuffer           aabbData;
     uint32_t           numAABBs;
     uint32_t           stride;
     VkDeviceSize       offset;
-} VkGeometryAABBNVX;
+} VkGeometryAABBNV;
 
-typedef struct VkGeometryDataNVX {
-    VkGeometryTrianglesNVX    triangles;
-    VkGeometryAABBNVX         aabbs;
-} VkGeometryDataNVX;
+typedef struct VkGeometryDataNV {
+    VkGeometryTrianglesNV    triangles;
+    VkGeometryAABBNV         aabbs;
+} VkGeometryDataNV;
 
-typedef struct VkGeometryNVX {
-    VkStructureType       sType;
-    const void*           pNext;
-    VkGeometryTypeNVX     geometryType;
-    VkGeometryDataNVX     geometry;
-    VkGeometryFlagsNVX    flags;
-} VkGeometryNVX;
+typedef struct VkGeometryNV {
+    VkStructureType      sType;
+    const void*          pNext;
+    VkGeometryTypeNV     geometryType;
+    VkGeometryDataNV     geometry;
+    VkGeometryFlagsNV    flags;
+} VkGeometryNV;
 
-typedef struct VkAccelerationStructureCreateInfoNVX {
-    VkStructureType                         sType;
-    const void*                             pNext;
-    VkAccelerationStructureTypeNVX          type;
-    VkBuildAccelerationStructureFlagsNVX    flags;
-    VkDeviceSize                            compactedSize;
-    uint32_t                                instanceCount;
-    uint32_t                                geometryCount;
-    const VkGeometryNVX*                    pGeometries;
-} VkAccelerationStructureCreateInfoNVX;
+typedef struct VkAccelerationStructureInfoNV {
+    VkStructureType                        sType;
+    const void*                            pNext;
+    VkAccelerationStructureTypeNV          type;
+    VkBuildAccelerationStructureFlagsNV    flags;
+    uint32_t                               instanceCount;
+    uint32_t                               geometryCount;
+    const VkGeometryNV*                    pGeometries;
+} VkAccelerationStructureInfoNV;
 
-typedef struct VkBindAccelerationStructureMemoryInfoNVX {
-    VkStructureType               sType;
-    const void*                   pNext;
-    VkAccelerationStructureNVX    accelerationStructure;
-    VkDeviceMemory                memory;
-    VkDeviceSize                  memoryOffset;
-    uint32_t                      deviceIndexCount;
-    const uint32_t*               pDeviceIndices;
-} VkBindAccelerationStructureMemoryInfoNVX;
+typedef struct VkAccelerationStructureCreateInfoNV {
+    VkStructureType                  sType;
+    const void*                      pNext;
+    VkDeviceSize                     compactedSize;
+    VkAccelerationStructureInfoNV    info;
+} VkAccelerationStructureCreateInfoNV;
 
-typedef struct VkDescriptorAccelerationStructureInfoNVX {
-    VkStructureType                      sType;
-    const void*                          pNext;
-    uint32_t                             accelerationStructureCount;
-    const VkAccelerationStructureNVX*    pAccelerationStructures;
-} VkDescriptorAccelerationStructureInfoNVX;
+typedef struct VkBindAccelerationStructureMemoryInfoNV {
+    VkStructureType              sType;
+    const void*                  pNext;
+    VkAccelerationStructureNV    accelerationStructure;
+    VkDeviceMemory               memory;
+    VkDeviceSize                 memoryOffset;
+    uint32_t                     deviceIndexCount;
+    const uint32_t*              pDeviceIndices;
+} VkBindAccelerationStructureMemoryInfoNV;
 
-typedef struct VkAccelerationStructureMemoryRequirementsInfoNVX {
-    VkStructureType               sType;
-    const void*                   pNext;
-    VkAccelerationStructureNVX    accelerationStructure;
-} VkAccelerationStructureMemoryRequirementsInfoNVX;
+typedef struct VkWriteDescriptorSetAccelerationStructureNV {
+    VkStructureType                     sType;
+    const void*                         pNext;
+    uint32_t                            accelerationStructureCount;
+    const VkAccelerationStructureNV*    pAccelerationStructures;
+} VkWriteDescriptorSetAccelerationStructureNV;
 
-typedef struct VkPhysicalDeviceRaytracingPropertiesNVX {
+typedef struct VkAccelerationStructureMemoryRequirementsInfoNV {
+    VkStructureType                                    sType;
+    const void*                                        pNext;
+    VkAccelerationStructureMemoryRequirementsTypeNV    type;
+    VkAccelerationStructureNV                          accelerationStructure;
+} VkAccelerationStructureMemoryRequirementsInfoNV;
+
+typedef struct VkPhysicalDeviceRayTracingPropertiesNV {
     VkStructureType    sType;
     void*              pNext;
-    uint32_t           shaderHeaderSize;
+    uint32_t           shaderGroupHandleSize;
     uint32_t           maxRecursionDepth;
-    uint32_t           maxGeometryCount;
-} VkPhysicalDeviceRaytracingPropertiesNVX;
+    uint32_t           maxShaderGroupStride;
+    uint32_t           shaderGroupBaseAlignment;
+    uint64_t           maxGeometryCount;
+    uint64_t           maxInstanceCount;
+    uint64_t           maxTriangleCount;
+    uint32_t           maxDescriptorSetAccelerationStructures;
+} VkPhysicalDeviceRayTracingPropertiesNV;
 
 
-typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNVX)(VkDevice device, const VkAccelerationStructureCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNVX* pAccelerationStructure);
-typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNVX)(VkDevice device, VkAccelerationStructureNVX accelerationStructure, const VkAllocationCallbacks* pAllocator);
-typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
-typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureScratchMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
-typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNVX)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos);
-typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureTypeNVX type, uint32_t instanceCount, VkBuffer instanceData, VkDeviceSize instanceOffset, uint32_t geometryCount, const VkGeometryNVX* pGeometries, VkBuildAccelerationStructureFlagsNVX flags, VkBool32 update, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkBuffer scratch, VkDeviceSize scratchOffset);
-typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkCopyAccelerationStructureModeNVX mode);
-typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNVX)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, uint32_t width, uint32_t height);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateRaytracingPipelinesNVX)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRaytracingPipelineCreateInfoNVX* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
-typedef VkResult (VKAPI_PTR *PFN_vkGetRaytracingShaderHandlesNVX)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData);
-typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNVX)(VkDevice device, VkAccelerationStructureNVX accelerationStructure, size_t dataSize, void* pData);
-typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructurePropertiesNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX accelerationStructure, VkQueryType queryType, VkQueryPool queryPool, uint32_t query);
-typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNVX)(VkDevice device, VkPipeline pipeline, uint32_t shader);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice device, const VkAccelerationStructureCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNV* pAccelerationStructure);
+typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
+typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV* pBindInfos);
+typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset);
+typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeNV mode);
+typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
+typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData);
+typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void* pData);
+typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery);
+typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNV)(VkDevice device, VkPipeline pipeline, uint32_t shader);
 
 #ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNV(
     VkDevice                                    device,
-    const VkAccelerationStructureCreateInfoNVX* pCreateInfo,
+    const VkAccelerationStructureCreateInfoNV*  pCreateInfo,
     const VkAllocationCallbacks*                pAllocator,
-    VkAccelerationStructureNVX*                 pAccelerationStructure);
+    VkAccelerationStructureNV*                  pAccelerationStructure);
 
-VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNVX(
+VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNV(
     VkDevice                                    device,
-    VkAccelerationStructureNVX                  accelerationStructure,
+    VkAccelerationStructureNV                   accelerationStructure,
     const VkAllocationCallbacks*                pAllocator);
 
-VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNVX(
+VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNV(
     VkDevice                                    device,
-    const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo,
+    const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo,
     VkMemoryRequirements2KHR*                   pMemoryRequirements);
 
-VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureScratchMemoryRequirementsNVX(
-    VkDevice                                    device,
-    const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo,
-    VkMemoryRequirements2KHR*                   pMemoryRequirements);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNV(
     VkDevice                                    device,
     uint32_t                                    bindInfoCount,
-    const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos);
+    const VkBindAccelerationStructureMemoryInfoNV* pBindInfos);
 
-VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNVX(
+VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNV(
     VkCommandBuffer                             commandBuffer,
-    VkAccelerationStructureTypeNVX              type,
-    uint32_t                                    instanceCount,
+    const VkAccelerationStructureInfoNV*        pInfo,
     VkBuffer                                    instanceData,
     VkDeviceSize                                instanceOffset,
-    uint32_t                                    geometryCount,
-    const VkGeometryNVX*                        pGeometries,
-    VkBuildAccelerationStructureFlagsNVX        flags,
     VkBool32                                    update,
-    VkAccelerationStructureNVX                  dst,
-    VkAccelerationStructureNVX                  src,
+    VkAccelerationStructureNV                   dst,
+    VkAccelerationStructureNV                   src,
     VkBuffer                                    scratch,
     VkDeviceSize                                scratchOffset);
 
-VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNVX(
+VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNV(
     VkCommandBuffer                             commandBuffer,
-    VkAccelerationStructureNVX                  dst,
-    VkAccelerationStructureNVX                  src,
-    VkCopyAccelerationStructureModeNVX          mode);
+    VkAccelerationStructureNV                   dst,
+    VkAccelerationStructureNV                   src,
+    VkCopyAccelerationStructureModeNV           mode);
 
-VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNVX(
+VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNV(
     VkCommandBuffer                             commandBuffer,
     VkBuffer                                    raygenShaderBindingTableBuffer,
     VkDeviceSize                                raygenShaderBindingOffset,
@@ -8167,18 +8374,22 @@
     VkBuffer                                    hitShaderBindingTableBuffer,
     VkDeviceSize                                hitShaderBindingOffset,
     VkDeviceSize                                hitShaderBindingStride,
+    VkBuffer                                    callableShaderBindingTableBuffer,
+    VkDeviceSize                                callableShaderBindingOffset,
+    VkDeviceSize                                callableShaderBindingStride,
     uint32_t                                    width,
-    uint32_t                                    height);
+    uint32_t                                    height,
+    uint32_t                                    depth);
 
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateRaytracingPipelinesNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesNV(
     VkDevice                                    device,
     VkPipelineCache                             pipelineCache,
     uint32_t                                    createInfoCount,
-    const VkRaytracingPipelineCreateInfoNVX*    pCreateInfos,
+    const VkRayTracingPipelineCreateInfoNV*     pCreateInfos,
     const VkAllocationCallbacks*                pAllocator,
     VkPipeline*                                 pPipelines);
 
-VKAPI_ATTR VkResult VKAPI_CALL vkGetRaytracingShaderHandlesNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesNV(
     VkDevice                                    device,
     VkPipeline                                  pipeline,
     uint32_t                                    firstGroup,
@@ -8186,20 +8397,21 @@
     size_t                                      dataSize,
     void*                                       pData);
 
-VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNV(
     VkDevice                                    device,
-    VkAccelerationStructureNVX                  accelerationStructure,
+    VkAccelerationStructureNV                   accelerationStructure,
     size_t                                      dataSize,
     void*                                       pData);
 
-VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructurePropertiesNVX(
+VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesNV(
     VkCommandBuffer                             commandBuffer,
-    VkAccelerationStructureNVX                  accelerationStructure,
+    uint32_t                                    accelerationStructureCount,
+    const VkAccelerationStructureNV*            pAccelerationStructures,
     VkQueryType                                 queryType,
     VkQueryPool                                 queryPool,
-    uint32_t                                    query);
+    uint32_t                                    firstQuery);
 
-VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNV(
     VkDevice                                    device,
     VkPipeline                                  pipeline,
     uint32_t                                    shader);
@@ -8296,6 +8508,46 @@
     uint32_t                                    marker);
 #endif
 
+#define VK_EXT_calibrated_timestamps 1
+#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 1
+#define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps"
+
+
+typedef enum VkTimeDomainEXT {
+    VK_TIME_DOMAIN_DEVICE_EXT = 0,
+    VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1,
+    VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2,
+    VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3,
+    VK_TIME_DOMAIN_BEGIN_RANGE_EXT = VK_TIME_DOMAIN_DEVICE_EXT,
+    VK_TIME_DOMAIN_END_RANGE_EXT = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT,
+    VK_TIME_DOMAIN_RANGE_SIZE_EXT = (VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT - VK_TIME_DOMAIN_DEVICE_EXT + 1),
+    VK_TIME_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkTimeDomainEXT;
+
+typedef struct VkCalibratedTimestampInfoEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkTimeDomainEXT    timeDomain;
+} VkCalibratedTimestampInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains);
+typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t*                                   pTimeDomainCount,
+    VkTimeDomainEXT*                            pTimeDomains);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetCalibratedTimestampsEXT(
+    VkDevice                                    device,
+    uint32_t                                    timestampCount,
+    const VkCalibratedTimestampInfoEXT*         pTimestampInfos,
+    uint64_t*                                   pTimestamps,
+    uint64_t*                                   pMaxDeviation);
+#endif
+
 #define VK_AMD_shader_core_properties 1
 #define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1
 #define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties"
@@ -8321,6 +8573,29 @@
 
 
 
+#define VK_AMD_memory_overallocation_behavior 1
+#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1
+#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior"
+
+
+typedef enum VkMemoryOverallocationBehaviorAMD {
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_BEGIN_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_END_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_RANGE_SIZE_AMD = (VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD + 1),
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_MAX_ENUM_AMD = 0x7FFFFFFF
+} VkMemoryOverallocationBehaviorAMD;
+
+typedef struct VkDeviceMemoryOverallocationCreateInfoAMD {
+    VkStructureType                      sType;
+    const void*                          pNext;
+    VkMemoryOverallocationBehaviorAMD    overallocationBehavior;
+} VkDeviceMemoryOverallocationCreateInfoAMD;
+
+
+
 #define VK_EXT_vertex_attribute_divisor 1
 #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3
 #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
@@ -8516,6 +8791,31 @@
     VkCheckpointDataNV*                         pCheckpointData);
 #endif
 
+#define VK_EXT_pci_bus_info 1
+#define VK_EXT_PCI_BUS_INFO_SPEC_VERSION  1
+#define VK_EXT_PCI_BUS_INFO_EXTENSION_NAME "VK_EXT_pci_bus_info"
+
+typedef struct VkPhysicalDevicePCIBusInfoPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint16_t           pciDomain;
+    uint8_t            pciBus;
+    uint8_t            pciDevice;
+    uint8_t            pciFunction;
+} VkPhysicalDevicePCIBusInfoPropertiesEXT;
+
+
+
+#define VK_GOOGLE_hlsl_functionality1 1
+#define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 0
+#define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1"
+
+
+#define VK_GOOGLE_decorate_string 1
+#define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 0
+#define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string"
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index 629ebb1..df86af0 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -556,6 +556,7 @@
         "vkGetDisplayModeProperties2KHR",
         "vkGetDisplayPlaneCapabilities2KHR",
         "vkGetInstanceProcAddr",
+        "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT",
         "vkGetPhysicalDeviceDisplayPlaneProperties2KHR",
         "vkGetPhysicalDeviceDisplayProperties2KHR",
         "vkGetPhysicalDeviceExternalBufferProperties",
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 1f4df1e..f04eb03 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -1149,6 +1149,7 @@
   {{else if eq $ext "VK_EXT_direct_mode_display"}}true
   {{else if eq $ext "VK_EXT_display_surface_counter"}}true
   {{else if eq $ext "VK_EXT_display_control"}}true
+  {{else if eq $ext "VK_FUCHSIA_imagepipe_surface"}}true
   {{else if eq $ext "VK_MVK_ios_surface"}}true
   {{else if eq $ext "VK_MVK_macos_surface"}}true
   {{else if eq $ext "VK_NN_vi_surface"}}true
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 57668a8..3da4336 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -325,6 +325,13 @@
   }
 };
 
+template <>
+struct EnumTraits<VkDriverIdKHR> {
+  static uint32_t min() { return VK_DRIVER_ID_BEGIN_RANGE_KHR; }
+  static uint32_t max() { return VK_DRIVER_ID_END_RANGE_KHR; }
+  static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+};
+
 // VkSparseImageFormatProperties
 
 template <typename Visitor>