Merge "SF: Map composition info by display token"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 4ccb917..08218b8 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -9,6 +9,7 @@
                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 a475fcc..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"
@@ -257,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;
-        }
     }
 
     {
@@ -988,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);
@@ -1037,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);
@@ -1202,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;
             }
         }
     }
@@ -1256,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;
             }
         }
     }
@@ -1445,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;
     }
 
@@ -1468,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");
@@ -1553,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();
 
@@ -1599,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();
 
@@ -1625,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
@@ -1707,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;
@@ -1716,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();
 
@@ -1776,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;
@@ -2564,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()) {
@@ -2585,17 +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;
-            }
-        }
-#endif
     }
     return ok();
 }
@@ -2613,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/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 174ab21..90cadb4 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,6 +201,34 @@
     }
 }
 
+// Automatically adds binary and null terminator arg.
+static inline void ExecVWithArgs(const char* bin, const std::vector<std::string>& args) {
+    std::vector<const char*> argv = {bin};
+    for (const std::string& arg : args) {
+        argv.push_back(arg.c_str());
+    }
+    // Add null terminator.
+    argv.push_back(nullptr);
+    execv(bin, (char * const *)&argv[0]);
+}
+
+static inline void AddArgIfNonEmpty(const std::string& arg, std::vector<std::string>* args) {
+    DCHECK(args != nullptr);
+    if (!arg.empty()) {
+        args->push_back(arg);
+    }
+}
+
+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 "";
+}
+
 [[ 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,
@@ -231,82 +236,50 @@
         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;
-
-    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);
-    }
-
     // 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;
+    std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
+    std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
 
-    char dex2oat_Xmx_flag[kPropertyValueMax];
-    bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, nullptr) > 0;
+    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");
 
-    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);
-    }
+    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");
 
-    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 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";
-    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);
+    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.
-    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)));
+    std::string vold_decrypt = GetProperty("vold.decrypt", "");
+    bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
+                            vold_decrypt == "1";
 
-    bool generate_debug_info = property_get_bool("debug.generate-debug-info", false);
-    const bool resolve_startup_strings =
-            property_get_bool("dalvik.vm.dex2oat-resolve-startup-strings", false);
+    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);
 
-    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);
+    std::string image_format_arg;
+    if (image_fd >= 0) {
+        image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
     }
 
-    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);
-    }
+    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";
@@ -323,113 +296,65 @@
             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];
+    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) {
-        snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s",
-            class_loader_context);
+        class_loader_context_arg = StringPrintf("--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);
+        dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
     }
     if (image_fd >= 0) {
-        have_dex2oat_image_fd = true;
-        sprintf(dex2oat_image_fd, "--app-image-fd=%d", image_fd);
+        dex2oat_image_fd = StringPrintf("--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;
+    bool have_dex2oat_relocation_skip_flag = false;
     if (skip_compilation) {
-        strlcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract",
-                sizeof(dex2oat_compiler_filter_arg));
-        have_dex2oat_compiler_filter_flag = true;
+        dex2oat_compiler_filter_arg = "--compiler-filter=extract";
         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);
-        }
+        dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
     }
 
-    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);
-        }
+    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) {
-        char prop_buf[kPropertyValueMax];
-        debuggable =
-                (get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&
-                (prop_buf[0] == '1');
+        debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
     }
-    char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN];
+    std::string profile_arg;
     if (profile_fd != -1) {
-        sprintf(profile_arg, "--profile-file-fd=%d", profile_fd);
+        profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
     }
 
     // Get the directory of the apk to pass as a base classpath directory.
-    char base_dir[arraysize("--classpath-dir=") + PKG_PATH_MAX];
+    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);
-        sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());
+        base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
     }
 
     std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
@@ -444,121 +369,69 @@
     // supported.
     const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
 
-    const char* argv[10  // 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;
-    argv[i++] = resolve_startup_strings ? "--resolve-startup-const-strings=true" :
-            "--resolve-startup-const-strings=false";
-    if (have_dex2oat_isa_variant) {
-        argv[i++] = instruction_set_variant_arg;
+    std::vector<std::string> args = {
+        zip_fd_arg,
+        zip_location_arg,
+        input_vdex_fd_arg,
+        output_vdex_fd_arg,
+        oat_fd_arg,
+        oat_location_arg,
+        instruction_set_arg,
+    };
+    auto add_runtime_arg = [&](const std::string& arg) {
+        args.push_back("--runtime-arg");
+        args.push_back(arg);
+    };
+
+    AddArgIfNonEmpty(instruction_set_variant_arg, &args);
+    AddArgIfNonEmpty(instruction_set_features_arg, &args);
+    if (!dex2oat_Xms_arg.empty()) {
+        add_runtime_arg(dex2oat_Xms_arg);
     }
-    if (have_dex2oat_isa_features) {
-        argv[i++] = instruction_set_features_arg;
+    if (!dex2oat_Xmx_arg.empty()) {
+        add_runtime_arg(dex2oat_Xmx_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;
-    }
+    AddArgIfNonEmpty(resolve_startup_string_arg, &args);
+    AddArgIfNonEmpty(dex2oat_compiler_filter_arg, &args);
+    AddArgIfNonEmpty(dex2oat_threads_arg, &args);
+    AddArgIfNonEmpty(dex2oat_swap_fd, &args);
+    AddArgIfNonEmpty(dex2oat_image_fd, &args);
+
     if (generate_debug_info) {
-        argv[i++] = "--generate-debug-info";
+        args.push_back("--generate-debug-info");
     }
     if (debuggable) {
-        argv[i++] = "--debuggable";
+        args.push_back("--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);
-    }
+    AddArgIfNonEmpty(image_format_arg, &args);
+    AddArgIfNonEmpty(dex2oat_large_app_threshold_arg, &args);
+    args.insert(args.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end());
     if (have_dex2oat_relocation_skip_flag) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = dex2oat_norelocation;
+        add_runtime_arg(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;
-    }
+    AddArgIfNonEmpty(profile_arg, &args);
+    AddArgIfNonEmpty(base_dir, &args);
+    AddArgIfNonEmpty(class_loader_context_arg, &args);
     if (generate_minidebug_info) {
-        argv[i++] = kMinidebugDex2oatFlag;
+        args.push_back(kMinidebugDex2oatFlag);
     }
     if (disable_cdex) {
-        argv[i++] = kDisableCompactDexFlag;
+        args.push_back(kDisableCompactDexFlag);
     }
-    if (target_sdk_version != 0) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = target_sdk_version_arg;
-    }
+    AddArgIfNonEmpty(target_sdk_version_arg, &args);
     if (enable_hidden_api_checks) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = "-Xhidden-api-checks";
+        add_runtime_arg("-Xhidden-api-checks");
     }
 
     if (dex_metadata_fd > -1) {
-        argv[i++] = dex_metadata_fd_arg.c_str();
+        args.push_back(dex_metadata_fd_arg);
     }
 
-    if(compilation_reason != nullptr) {
-        argv[i++] = compilation_reason_arg.c_str();
-    }
+    AddArgIfNonEmpty(compilation_reason_arg, &args);
+
     // Do not add after dex2oat_flags, they should override others for debugging.
-    argv[i] = nullptr;
 
-    execv(dex2oat_bin, (char * const *)argv);
+    ExecVWithArgs(dex2oat_bin, args);
     PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
     exit(DexoptReturnCodes::kDex2oatExec);
 }
@@ -584,13 +457,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
@@ -600,8 +469,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;
     }
 
@@ -755,50 +623,33 @@
         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> args;
+    args.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
 
-    std::vector<std::string> apk_args;
+    for (const unique_fd& fd : profile_fds) {
+        args.push_back("--profile-file-fd=" + std::to_string(fd.get()));
+    }
+
     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()));
+        for (const unique_fd& fd : *apk_fds) {
+            args.push_back("--apk-fd=" + std::to_string(fd.get()));
         }
     }
 
     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]);
+        for (const std::string& dex_location : *dex_locations) {
+            args.push_back("--dex-location=" + dex_location);
         }
     }
 
-    // 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";
+        args.push_back("--copy-and-update-profile-key");
     }
 
     // Do not add after dex2oat_flags, they should override others for debugging.
-    argv[i] = nullptr;
 
-    execv(profman_bin, (char * const *)argv);
+    ExecVWithArgs(profman_bin, args);
     PLOG(ERROR) << "execv(" << profman_bin << ") failed";
     exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
 }
@@ -931,7 +782,6 @@
                              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) {
@@ -947,14 +797,8 @@
     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);
+    ExecVWithArgs(PROFMAN_BIN, profman_args);
     PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
     exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
 }
@@ -1310,10 +1154,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
@@ -1583,13 +1425,6 @@
             is_debug_runtime()
                     ? "/system/bin/dexoptanalyzerd"
                     : "/system/bin/dexoptanalyzer";
-    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
-
-    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);
@@ -1604,38 +1439,30 @@
         class_loader_context_arg += class_loader_context;
     }
 
-    // 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();
+    // program name, dex file, isa, filter
+    std::vector<std::string> args = {
+      dex_file_arg,
+      isa_arg,
+      compiler_filter_arg,
+    };
     if (oat_fd >= 0) {
-        argv[i++] = oat_fd_arg.c_str();
+        args.push_back(oat_fd_arg);
     }
     if (vdex_fd >= 0) {
-        argv[i++] = vdex_fd_arg.c_str();
+        args.push_back(vdex_fd_arg);
     }
-    argv[i++] = zip_fd_arg.c_str();
+    args.push_back(zip_fd_arg.c_str());
     if (profile_was_updated) {
-        argv[i++] = assume_profile_changed;
+        args.push_back(assume_profile_changed);
     }
     if (downgrade) {
-        argv[i++] = downgrade_flag;
+        args.push_back(downgrade_flag);
     }
     if (class_loader_context != nullptr) {
-        argv[i++] = class_loader_context_arg.c_str();
+        args.push_back(class_loader_context_arg.c_str());
     }
-    argv[i] = nullptr;
 
-    execv(dexoptanalyzer_bin, (char * const *)argv);
+    ExecVWithArgs(dexoptanalyzer_bin, args);
     ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
 }
 
@@ -2425,18 +2252,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.
@@ -2693,6 +2516,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);
 
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/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 0b89879..caf2318 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -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) {
@@ -227,6 +229,7 @@
 BnMemory::~BnMemory() {
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnMemory::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -391,6 +394,7 @@
 BnMemoryHeap::~BnMemoryHeap() {
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnMemoryHeap::onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
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/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..14edcbe 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -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 11f7efa..071946f 100644
--- a/libs/binder/include/binder/IMemory.h
+++ b/libs/binder/include/binder/IMemory.h
@@ -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/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..e1c2009 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -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/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index cc0a29d..e52a1d6 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -31,6 +31,7 @@
 #include <android/binder_status.h>
 
 #include <assert.h>
+#include <unistd.h>
 
 #ifdef __cplusplus
 
@@ -113,23 +114,23 @@
 /**
  * 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:
     /**
      * 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 +138,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 +157,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;
@@ -167,13 +168,13 @@
     ScopedAResource(ScopedAResource&&) = default;
 
 private:
-    T* mT;
+    T mT;
 };
 
 /**
  * Convenience wrapper. See AParcel.
  */
-class ScopedAParcel : public ScopedAResource<AParcel, AParcel_delete> {
+class ScopedAParcel : public ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
 public:
     /**
      * Takes ownership of a.
@@ -186,7 +187,7 @@
 /**
  * Convenience wrapper. See AStatus.
  */
-class ScopedAStatus : public ScopedAResource<AStatus, AStatus_delete> {
+class ScopedAStatus : public ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
 public:
     /**
      * Takes ownership of a.
@@ -205,7 +206,8 @@
  * Convenience wrapper. See AIBinder_DeathRecipient.
  */
 class ScopedAIBinder_DeathRecipient
-      : public ScopedAResource<AIBinder_DeathRecipient, AIBinder_DeathRecipient_delete> {
+      : public ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
+                               nullptr> {
 public:
     /**
      * Takes ownership of a.
@@ -219,7 +221,8 @@
 /**
  * Convenience wrapper. See AIBinder_Weak.
  */
-class ScopedAIBinder_Weak : public ScopedAResource<AIBinder_Weak, AIBinder_Weak_delete> {
+class ScopedAIBinder_Weak
+      : public ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
 public:
     /**
      * Takes ownership of a.
@@ -234,6 +237,19 @@
     SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
 };
 
+/**
+ * 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;
+};
+
 } // namespace ndk
 
 #endif // __cplusplus
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index d36b3c0..a303f4a 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -51,99 +51,159 @@
 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.
  */
-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
+ */
+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
+ */
+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
+ */
+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
  */
-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
  */
-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
  */
-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
  */
-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
  */
-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
  */
-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
+ */
+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
  */
 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
  */
 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
  */
-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
  */
-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
- *
- * 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'.
- *
- * 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.
  */
 binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) __INTRODUCED_IN(29);
@@ -163,6 +223,23 @@
         __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.
+ */
+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.
+ */
+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
@@ -182,24 +259,44 @@
         __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.
  */
 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.
- *
- * 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.
+ * 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.
  */
-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.
+ */
+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.
+ */
+binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData,
+                                        AParcel_stringArrayAllocator allocator,
+                                        AParcel_stringArrayElementAllocator elementAllocator)
         __INTRODUCED_IN(29);
 
 // @START-PRIMITIVE-READ-WRITE
@@ -331,10 +428,12 @@
 
 /**
  * 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.
  */
-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.
@@ -350,66 +449,93 @@
 
 /**
  * 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
  */
-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
  */
-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
  */
-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
  */
-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
  */
-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
  */
-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.
  */
-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
  */
-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
  */
-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
 
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 bf0c956..3fcb121 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -36,24 +36,34 @@
 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;
 }
 
 /**
@@ -89,8 +99,7 @@
  */
 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>);
 }
 
 /**
@@ -105,8 +114,7 @@
  */
 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>);
 }
 
 /**
@@ -121,8 +129,7 @@
  */
 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>);
 }
 
 /**
@@ -137,8 +144,7 @@
  */
 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>);
 }
 
 /**
@@ -153,8 +159,7 @@
  */
 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>);
 }
 
 /**
@@ -169,16 +174,15 @@
  */
 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.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) {
-    return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec),
-                                  AParcel_stdVectorGetter<bool>, vec.size());
+    return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), vec.size(),
+                                  AParcel_stdVectorGetter<bool>);
 }
 
 /**
@@ -186,7 +190,7 @@
  */
 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>);
 }
 
@@ -202,8 +206,7 @@
  */
 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>);
 }
 
 /**
@@ -218,28 +221,45 @@
  */
 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();
 }
 
 /**
@@ -254,8 +274,28 @@
  */
 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);
 }
 
 template <typename T>
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..3b44a62 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
@@ -413,9 +487,9 @@
     return WriteArray<double>(parcel, value, 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) {
@@ -426,58 +500,50 @@
     return WriteArray<int8_t>(parcel, value, 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/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
index 2cf10d3..0e10220 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -89,73 +89,98 @@
     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"
+        arg_types = "const " + cpp + "* value, size_t length"
+        if nca: arg_types = "const void* arrayData, size_t length, AParcel_" + pretty.lower() + "ArrayGetter getter"
         args = "value, length"
-        if nca: args = "arrayData, getter, length, &Parcel::write" + pretty
+        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 += "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 += "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 += "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 += "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 += "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 += "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 += "inline binder_status_t AParcel_writeVector(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"
+        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"
@@ -165,9 +190,12 @@
         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/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 024d72b..97b4828 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -145,18 +145,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 +204,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..528c260 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -58,10 +58,12 @@
     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;
@@ -74,6 +76,7 @@
     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 +85,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/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 cf9d4c5..e66c0e5 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -565,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) {
@@ -578,11 +580,28 @@
         }
         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 bool isColorManagementUsed() const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::IS_COLOR_MANAGEMET_USED, data, &reply);
+        int32_t result = 0;
+        status_t err = reply.readInt32(&result);
+        if (err != NO_ERROR) {
+            ALOGE("ISurfaceComposer::isColorManagementUsed: error "
+                  "retrieving result: %s (%d)",
+                  strerror(-err), -err);
+            return false;
+        }
+        return result != 0;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -910,16 +929,28 @@
         }
         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 IS_COLOR_MANAGEMET_USED: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            int32_t result = isColorManagementUsed() ? 1 : 0;
+            reply->writeInt32(result);
+            return NO_ERROR;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7498f36..e5a2454 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -866,9 +866,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() {
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 781e062..9316ae6 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -280,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 bool isColorManagementUsed() 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;
 };
 
 // ----------------------------------------------------------------------------
@@ -320,6 +331,7 @@
         GET_LAYER_DEBUG_INFO,
         CREATE_SCOPED_CONNECTION,
         GET_COMPOSITION_PREFERENCE,
+        IS_COLOR_MANAGEMET_USED,
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 1b4eda7..8ccee05 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -101,9 +101,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
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 500df05..a3e9249 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -628,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 bool isColorManagementUsed() const { return false; }
+
 protected:
     IBinder* onAsBinder() override { return nullptr; }
 
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 5fbb3b2..647fe86 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",
@@ -70,6 +77,7 @@
 
     header_libs: [
         "libnativebase_headers",
+        "libnativewindow_headers",
     ],
 
     // headers we include in our public headers
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 674659c..7efc8bd 100644
--- a/libs/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: [
@@ -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/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index a6e6d73..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>
 
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/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 f0253b2..a247e60 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,7 +16,10 @@
 
 #define LOG_TAG "BufferHubBufferTest"
 
+#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 {
@@ -32,13 +35,18 @@
 
 } // 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::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 +83,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 +106,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 client_state_mask() to tell those two instances apart.
-    EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
-    EXPECT_NE(b1->client_state_mask(), 0ULL);
-    EXPECT_NE(b2->client_state_mask(), 0ULL);
-    EXPECT_NE(b1->client_state_mask(), kProducerStateBit);
-    EXPECT_NE(b2->client_state_mask(), kProducerStateBit);
+    EXPECT_NE(bufferStateMask1, bufferStateMask2);
 
     // Both buffer instances should be in gained state.
     EXPECT_TRUE(IsBufferGained(b1->buffer_state()));
@@ -115,4 +123,14 @@
     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;
+    sp<IBase> interface = bufferhub->importBuffer(handle);
+    EXPECT_EQ(nullptr, interface.get());
+}
+
 } // 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/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 3e26dae..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,14 +61,14 @@
   ASSERT_TRUE(c2.get() != nullptr);
 
   // Producer state mask is unique, i.e. 1.
-  EXPECT_EQ(p->client_state_mask(), kProducerStateBit);
+  EXPECT_EQ(p->client_state_mask(), kFirstClientBitMask);
   // Consumer state mask cannot have producer bit on.
-  EXPECT_EQ(c->client_state_mask() & 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->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->client_state_mask() & 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->client_state_mask(), 0U);
   EXPECT_EQ(c2->client_state_mask() & (c2->client_state_mask() - 1), 0U);
@@ -187,7 +189,7 @@
     EXPECT_EQ(client_state_masks & cs[i]->client_state_mask(), 0U);
     client_state_masks |= cs[i]->client_state_mask();
   }
-  EXPECT_EQ(client_state_masks, kProducerStateBit | kConsumerStateMask);
+  EXPECT_EQ(client_state_masks, kFirstClientBitMask | kConsumerStateMask);
 
   // The 64th creation will fail with out-of-memory error.
   auto state = p->CreateConsumer();
@@ -202,7 +204,7 @@
     // The released state mask will be reused.
     EXPECT_EQ(client_state_masks & cs[i]->client_state_mask(), 0U);
     client_state_masks |= cs[i]->client_state_mask();
-    EXPECT_EQ(client_state_masks, kProducerStateBit | kConsumerStateMask);
+    EXPECT_EQ(client_state_masks, kFirstClientBitMask | kConsumerStateMask);
   }
 }
 
@@ -707,7 +709,7 @@
   std::unique_ptr<ConsumerBuffer> c1 =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c1.get() != nullptr);
-  const uint64_t consumer_state_bit1 = c1->client_state_mask();
+  const uint64_t client_state_mask1 = c1->client_state_mask();
 
   DvrNativeBufferMetadata meta;
   EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
@@ -723,8 +725,8 @@
   std::unique_ptr<ConsumerBuffer> c2 =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c2.get() != nullptr);
-  const uint64_t consumer_state_bit2 = c2->client_state_mask();
-  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)));
@@ -739,8 +741,8 @@
   std::unique_ptr<ConsumerBuffer> c3 =
       ConsumerBuffer::Import(p->CreateConsumer());
   ASSERT_TRUE(c3.get() != nullptr);
-  const uint64_t consumer_state_bit3 = c3->client_state_mask();
-  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));
@@ -888,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);
@@ -905,6 +908,7 @@
   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();
 
@@ -913,10 +917,6 @@
   EXPECT_EQ(b1_id, b2_id);
   // We use client_state_mask() to tell those two instances apart.
   EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
-  EXPECT_NE(b1->client_state_mask(), 0ULL);
-  EXPECT_NE(b2->client_state_mask(), 0ULL);
-  EXPECT_NE(b1->client_state_mask(), kProducerStateBit);
-  EXPECT_NE(b2->client_state_mask(), kProducerStateBit);
 
   // 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 b4c5d42..68cc766 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -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;
 }
diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp
index a91e842..8e630ec 100644
--- a/libs/vr/libbufferhub/consumer_buffer.cpp
+++ b/libs/vr/libbufferhub/consumer_buffer.cpp
@@ -38,7 +38,7 @@
   // 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();
+  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
           " client_state_mask=%" PRIx64 ".",
@@ -57,9 +57,10 @@
     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();
   }
 
@@ -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 1ea8302..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,7 +90,9 @@
   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.
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 4953f9b..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 {
@@ -122,7 +123,7 @@
 
   // 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 client_state_mask() const { return client_state_mask_; }
   uint64_t metadata_size() const { return metadata_size_; }
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index de51f25..5ff4e00 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -122,9 +122,7 @@
   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.
+  // 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_); }
@@ -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/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index 8f0e3e3..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;
 }
 
@@ -135,7 +136,7 @@
 
 int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta,
                               LocalHandle* out_fence, bool gain_posted_buffer) {
-  uint64_t buffer_state = buffer_state_->load();
+  uint64_t buffer_state = buffer_state_->load(std::memory_order_acquire);
   ALOGD_IF(TRACE, "ProducerBuffer::LocalGain: buffer=%d, state=%" PRIx64 ".",
            id(), buffer_state);
 
@@ -168,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();
@@ -228,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
@@ -242,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/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 a7fea33..a150db1 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -36,6 +36,7 @@
 #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*);
@@ -274,10 +275,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,
@@ -524,16 +539,15 @@
     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();
+    const char* app_pref = android::GraphicsEnv::getInstance().getAngleAppPref();
+    bool developer_opt_in = android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
+    const int rules_fd = android::GraphicsEnv::getInstance().getAngleRulesFd();
+    const long rules_offset = android::GraphicsEnv::getInstance().getAngleRulesOffset();
+    const long rules_length = android::GraphicsEnv::getInstance().getAngleRulesLength();
 
     // Determine whether or not to use ANGLE:
     ANGLEPreference developer_option = developer_opt_in ? ANGLE_PREFER_ANGLE : ANGLE_NO_PREFERENCE;
@@ -541,6 +555,8 @@
 
     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:
@@ -550,19 +566,13 @@
         property_get("ro.product.manufacturer", manufacturer, "UNSET");
         property_get("ro.product.model", model, "UNSET");
 
-        // Check if ANGLE is enabled. Workaround for b/118375731
-        // We suspect that loading & unloading a library somehow corrupts
-        // the process.
-        property_get("debug.angle.enable", prop, "0");
-        if (atoi(prop)) {
-            so = load_angle_from_namespace("feature_support", ns);
-        }
-        if (so) {
-            ALOGV("Temporarily loaded ANGLE's opt-in/out logic from namespace");
+        cnx->featureSo = load_angle_from_namespace("feature_support", ns);
+        if (cnx->featureSo) {
+            ALOGV("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");
+                    (fpANGLEGetUtilityAPI)dlsym(cnx->featureSo, "ANGLEGetUtilityAPI");
             if (ANGLEGetUtilityAPI) {
                 unsigned int versionToUse = 1;
                 if ((ANGLEGetUtilityAPI)(&versionToUse)) {
@@ -574,12 +584,13 @@
                 }
             } else {
                 use_version0_API = true;
+                ALOGV("Cannot find ANGLEGetUtilityAPI in library");
             }
             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");
+                        (fpAndroidUseANGLEForApplication)dlsym(cnx->featureSo, "AndroidUseANGLEForApplication");
                 if (AndroidUseANGLEForApplication) {
                     use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
                                                                 rules_length, app_name_str.c_str(),
@@ -591,9 +602,10 @@
                 // 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");
+                        (fpANGLEUseForApplication)dlsym(cnx->featureSo, "ANGLEUseForApplication");
                 if (ANGLEUseForApplication) {
-                    ANGLEPreference app_preference = getAnglePref(android_getAngleAppPref());
+                    ANGLEPreference app_preference =
+                            getAnglePref(android::GraphicsEnv::getInstance().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");
@@ -601,16 +613,15 @@
                     ALOGW("Cannot find ANGLEUseForApplication in library");
                 }
             }
-            ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
-            dlclose(so);
-            so = nullptr;
         } 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);
     }
@@ -618,13 +629,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;
@@ -667,13 +695,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/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
new file mode 100644
index 0000000..d03d833
--- /dev/null
+++ b/services/bufferhub/Android.bp
@@ -0,0 +1,70 @@
+//
+// 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: [
+        "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/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
new file mode 100644
index 0000000..8be85a5
--- /dev/null
+++ b/services/bufferhub/BufferHubService.cpp
@@ -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.
+ */
+
+#include <bufferhub/BufferHubService.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::status_t;
+using ::android::hardware::Void;
+
+Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& /*description*/,
+                                              allocateBuffer_cb /*hidl_cb*/) {
+    return Void();
+}
+
+Return<sp<IBase>> BufferHubService::importBuffer(const hidl_handle& /*nativeHandle*/) {
+    return nullptr;
+}
+
+} // 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..62583a6
--- /dev/null
+++ b/services/bufferhub/BufferNode.cpp
@@ -0,0 +1,100 @@
+#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("BufferNode::BufferNode: Failed to allocate buffer: %s", 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("BufferNode::BufferNode: Failed to allocate metadata.");
+        return;
+    }
+    InitializeMetadata();
+}
+
+// Free the handle
+BufferNode::~BufferNode() {
+    if (buffer_handle_ != nullptr) {
+        status_t ret = GraphicBufferAllocator::get().free(buffer_handle_);
+        if (ret != OK) {
+            ALOGE("BufferNode::~BufferNode: Failed to free handle; Got error: %d", 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("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 | 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/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
new file mode 100644
index 0000000..b273e5b
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -0,0 +1,48 @@
+/*
+ * 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/IBufferHub.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::Return;
+using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
+using ::android::hidl::base::V1_0::IBase;
+
+class BufferHubService : public IBufferHub {
+public:
+    Return<void> allocateBuffer(const HardwareBufferDescription& /*description*/,
+                                allocateBuffer_cb /*hidl_cb*/) override;
+    Return<sp<IBase>> importBuffer(const hidl_handle& /*nativeHandle*/) 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/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/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e592a8b..c130bc5 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);
 }
@@ -380,7 +378,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) {
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index abe0bc7..c9ebe04 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;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 5df8ade..73098bf 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -470,8 +470,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);
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 88c3c8a..f29dfc0 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
 // ---------------------------------------------------------------------------
@@ -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 {
@@ -752,6 +762,9 @@
         // relevant frame
         return false;
     }
+    if (isRemovedFromCurrentState()) {
+        return false;
+    }
 
     Mutex::Autolock lock(mLocalSyncPointMutex);
     mLocalSyncPoints.push_back(point);
@@ -825,7 +838,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());
@@ -1476,9 +1491,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);
@@ -1995,6 +2009,10 @@
     }
 }
 
+bool Layer::isRemovedFromCurrentState() const  {
+    return mRemovedFromCurrentState;
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 5d05f05..12671ff 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -346,7 +346,7 @@
     virtual bool isCreatedFromMainThread() const { return false; }
 
 
-    bool isPendingRemoval() const { return mPendingRemoval; }
+    bool isRemovedFromCurrentState() const;
 
     void writeToProto(LayerProto* layerInfo,
                       LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
@@ -394,8 +394,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 { }
 
@@ -475,12 +473,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;
@@ -595,12 +587,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 +694,8 @@
     virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
     bool getPremultipledAlpha() const;
 
+    bool mPendingHWCDestroy{false};
+
 protected:
     // -----------------------------------------------------------------------
     bool usingRelativeZ(LayerVector::StateSet stateSet);
@@ -745,7 +739,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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f61d0b1..4c3be4d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -196,8 +196,10 @@
 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] = {};
@@ -303,10 +305,13 @@
     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;
+                });
     }
 
     useContextPriority = getBool<ISurfaceFlingerConfigs,
@@ -513,6 +518,10 @@
     return mDisplayTokens[id];
 }
 
+bool SurfaceFlinger::isColorManagementUsed() const {
+    return useColorManagement;
+}
+
 void SurfaceFlinger::bootFinished()
 {
     if (mStartPropertySetThread->join() != NO_ERROR) {
@@ -634,8 +643,8 @@
 
     // 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,
@@ -1153,10 +1162,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 = defaultCompositionDataspace;
+    *outPixelFormat = defaultCompositionPixelFormat;
+    *outWideColorGamutDataspace = wideColorGamutCompositionDataspace;
+    *outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat;
     return NO_ERROR;
 }
 
@@ -2712,7 +2725,15 @@
         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();
+                l->releasePendingBuffer(systemTime());
+            }
         }
         mLayersPendingRemoval.clear();
     }
@@ -3145,7 +3166,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;
             }
@@ -3161,7 +3182,6 @@
                                 mMaxGraphicBufferProducerListSize, mNumLayers);
         }
         mLayersAdded = true;
-        mNumLayers++;
     }
 
     // attach this layer to the client
@@ -3175,52 +3195,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;
 }
 
@@ -3421,11 +3411,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;
@@ -3629,11 +3614,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);
     }
@@ -3807,17 +3787,16 @@
     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);
 }
 
 // ---------------------------------------------------------------------------
@@ -4730,6 +4709,7 @@
         case SET_TRANSACTION_STATE:
         // Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
         case CREATE_SCOPED_CONNECTION:
+        case IS_COLOR_MANAGEMET_USED:
         case GET_COMPOSITION_PREFERENCE: {
             return OK;
         }
@@ -5161,7 +5141,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;
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 675e92b..0747c05 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -294,8 +294,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";
@@ -358,6 +364,9 @@
     bool authenticateSurfaceTextureLocked(
         const sp<IGraphicBufferProducer>& bufferProducer) const;
 
+    inline void onLayerCreated() { mNumLayers++; }
+    inline void onLayerDestroyed() { mNumLayers--; }
+
 private:
     friend class Client;
     friend class DisplayEventConnection;
@@ -460,8 +469,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 bool isColorManagementUsed() const;
+    status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
+                                      ui::Dataspace* outWideColorGamutDataspace,
+                                      ui::PixelFormat* outWideColorGamutPixelFormat) const override;
 
     /* ------------------------------------------------------------------------
      * DeathRecipient interface
@@ -567,10 +578,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);
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 43fa262..ace7c1b 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -241,25 +241,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 +444,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 +495,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 +513,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 +544,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 +556,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 +576,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/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 3166a8c..57a2227 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -30,6 +30,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>
@@ -314,6 +315,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);
+        mColorManagementUsed = sf->isColorManagementUsed();
     }
 
     virtual void TearDown() {
@@ -470,6 +475,8 @@
     void setMatrixWithResizeHelper(uint32_t layerType);
 
     sp<SurfaceControl> mBlackBgSurface;
+    bool mColorManagementUsed;
+
 private:
     void SetUpDisplay() {
         mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
@@ -2064,6 +2071,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(
@@ -2076,19 +2124,35 @@
     }
 
     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);
     }
 }
 
@@ -2550,6 +2614,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/thermalservice/libthermalcallback/ThermalChangedCallback.cpp b/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp
index 0efd732..bb48387 100644
--- a/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp
+++ b/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp
@@ -68,6 +68,8 @@
                              static_cast<size_t>(ThrottlingSeverity::SEVERE))
                 ? true
                 : false;
+        value = temperature.value == UNKNOWN_TEMPERATURE ? NAN :
+                temperature.value;
         android::os::Temperature thermal_svc_temp(value, type);
         mThermalService->notifyThrottling(isThrottling, thermal_svc_temp);
     } else {
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 bccfe67..589b31a 100644
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -13,15 +13,6 @@
 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)) {
-  client_state_mask_ = 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)
@@ -58,9 +49,9 @@
 
 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);
 }
@@ -94,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(),
       /*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 f8a9758..afd34aa 100644
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ b/services/vr/bufferhubd/buffer_hub_binder.cpp
@@ -65,18 +65,65 @@
   return NO_ERROR;
 }
 
+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());
+
+  token_map_.emplace(*outToken, node);
+  return NO_ERROR;
+}
+
 sp<IBufferClient> BufferHubBinderService::createBuffer(
     uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
     uint64_t usage, uint64_t user_metadata_size) {
   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 e74a21f..0000000
--- a/services/vr/bufferhubd/buffer_node.cpp
+++ /dev/null
@@ -1,75 +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);
-  if (!metadata_.IsValid()) {
-    ALOGE("BufferNode::BufferNode: Failed to allocate metadata.");
-    return;
-  }
-  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 client_state_mask = 0ULL;
-  uint64_t updated_active_clients_bit_mask = 0ULL;
-  do {
-    client_state_mask =
-        BufferHubDefs::FindNextClearedBit(current_active_clients_bit_mask);
-    if (client_state_mask == 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 | 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 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/include/private/dvr/IBufferHub.h b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
index bd5f9cf..502c6d6 100644
--- a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
+++ b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
@@ -17,6 +17,9 @@
                                          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 6d1e9e1..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,
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 9064d87..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,20 +18,33 @@
                                public BnBufferHub {
  public:
   static status_t start(const std::shared_ptr<BufferHubService>& pdx_service);
-  // 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;
 
+  // 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,
                                  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;
+
  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 067584e..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 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.
-  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 client_state_mask 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..8f35437 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
@@ -42,7 +42,7 @@
  private:
   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.
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index b5c92be..5868b09 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -42,7 +42,9 @@
 
   ~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;
@@ -108,7 +110,6 @@
   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);
 
   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 beedc4c..241eee7 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,11 +224,6 @@
           *this, &ProducerChannel::OnProducerGain, message);
       return true;
 
-    case BufferHubRPC::ProducerBufferDetach::Opcode:
-      DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
-          *this, &ProducerChannel::OnProducerDetach, message);
-      return true;
-
     default:
       return false;
   }
@@ -241,8 +244,8 @@
     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) {
@@ -266,10 +269,9 @@
   // 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) {
+  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.");
@@ -277,7 +279,7 @@
   }
 
   uint64_t updated_active_clients_bit_mask =
-      current_active_clients_bit_mask | consumer_state_bit;
+      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
@@ -287,15 +289,15 @@
   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 ".",
+    ALOGE("Current active clients bit mask is changed to %" PRIx64
+          ", which was expected to be %" PRIx64 ".",
           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());
+                                        client_state_mask, shared_from_this());
   const auto channel_status = service()->SetChannel(channel_id, consumer);
   if (!channel_status) {
     ALOGE(
@@ -304,13 +306,13 @@
         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,
+    active_clients_bit_mask_->fetch_and(~client_state_mask,
                                         std::memory_order_release);
     return ErrorStatus(ENOMEM);
   }
 
-  if (!producer_owns_ &&
-      !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
+  if (!producer_owns_ && !BufferHubDefs::IsBufferReleased(
+                             buffer_state_->load(std::memory_order_acquire))) {
     // Signal the new consumer when adding it to a posted producer.
     if (consumer->OnProducerPosted())
       pending_consumers_++;
@@ -403,13 +405,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 +459,7 @@
   }
 
   return status;
-}
+} */
 
 Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
   ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
@@ -505,11 +509,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 +528,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 +554,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 +585,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 +601,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 7fa2226..7c00fa6 100644
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
@@ -10,6 +10,7 @@
 
 namespace {
 
+using testing::IsNull;
 using testing::NotNull;
 
 const int kWidth = 640;
@@ -38,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 9a927f1..0000000
--- a/services/vr/bufferhubd/tests/buffer_node-test.cpp
+++ /dev/null
@@ -1,91 +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_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 < 64; ++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 dvr
-}  // namespace android
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index e5b9b47..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 90
+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
@@ -526,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
@@ -565,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"
@@ -693,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  //
@@ -794,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 {
@@ -806,8 +808,8 @@
     //@extension("VK_EXT_transform_feedback") // 29
     VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT             = 1000028004,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_QUERY_TYPE_COMPACTED_SIZE_NVX                        = 1000165000,
+    //@extension("VK_NV_raytracing") // 166
+    VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV  = 1000165000,
 }
 
 enum VkBorderColor {
@@ -823,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 {
@@ -849,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 {
@@ -1447,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,
 
@@ -1786,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,
@@ -1830,6 +1832,9 @@
     //@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,
@@ -2011,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,
 }
 
 
@@ -2135,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
@@ -2311,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
@@ -2345,6 +2364,13 @@
     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,
@@ -2433,9 +2459,9 @@
     //@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,
@@ -2459,8 +2485,8 @@
     //@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,
@@ -2491,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,
@@ -2595,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
@@ -2791,8 +2817,9 @@
     //@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,
@@ -3194,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
@@ -3484,33 +3505,33 @@
     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
@@ -5330,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
@@ -7249,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
@@ -7280,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
@@ -7290,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
@@ -7454,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
@@ -10370,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,
@@ -11448,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,
@@ -11522,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,
@@ -11548,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) {
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 ac9bb66..4cd8ed5 100644
--- a/vulkan/include/vulkan/vulkan_core.h
+++ b/vulkan/include/vulkan/vulkan_core.h
@@ -43,13 +43,12 @@
 #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 90
+#define VK_HEADER_VERSION 91
 
 
 #define VK_NULL_HANDLE 0
 
 
-
 #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
 
 
@@ -62,7 +61,6 @@
 #endif
 
 
-
 typedef uint32_t VkFlags;
 typedef uint32_t VkBool32;
 typedef uint64_t VkDeviceSize;
@@ -287,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,
@@ -419,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,
@@ -440,6 +437,7 @@
     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,
@@ -848,7 +846,7 @@
     VK_QUERY_TYPE_PIPELINE_STATISTICS = 1,
     VK_QUERY_TYPE_TIMESTAMP = 2,
     VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004,
-    VK_QUERY_TYPE_COMPACTED_SIZE_NVX = 1000165000,
+    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),
@@ -1178,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),
@@ -1207,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),
@@ -1226,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),
@@ -1279,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,
@@ -1447,7 +1446,8 @@
     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
@@ -1544,7 +1544,7 @@
     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;
@@ -1559,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
@@ -1576,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
@@ -1673,8 +1673,8 @@
     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;
@@ -6182,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,
@@ -8113,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;
@@ -8201,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,
@@ -8340,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,
@@ -8359,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);
@@ -8534,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"