Merge "[RESTRICT AUTOMERGE] Revert "libEGL: When driver doesn't understand P3, map sRGB-encoded P3 to sRGB""
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 2d780f5..73360a3 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,3 +1,17 @@
+[Builtin Hooks]
+clang_format = true
+
+[Builtin Hooks Options]
+# Only turn on clang-format check for the following subfolders.
+clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+               libs/binder/ndk/
+               libs/graphicsenv/
+               libs/gui/
+               libs/ui/
+               libs/vr/
+               services/surfaceflinger/
+               services/vr/
+
 [Hook Scripts]
 owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$"
 installd_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/installd/"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index e897482..19c2830 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -224,6 +224,11 @@
     { "pagecache",  "Page cache", 0, {
         { REQ,      "events/filemap/enable" },
     } },
+    { "memory",  "Memory", 0, {
+        { OPT,      "events/kmem/rss_stat/enable" },
+        { OPT,      "events/kmem/ion_heap_grow/enable" },
+        { OPT,      "events/kmem/ion_heap_shrink/enable" },
+    } },
 };
 
 struct TracingVendorCategory {
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index d950b7c..4459cef 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -91,7 +91,20 @@
     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
+    chmod 0666 /sys/kernel/debug/tracing/events/signal/signal_generate/enable
+    chmod 0666 /sys/kernel/tracing/events/signal/signal_generate/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/signal/signal_deliver/enable
+    chmod 0666 /sys/kernel/tracing/events/signal/signal_deliver/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/mm_event/mm_event_record/enable
+    chmod 0666 /sys/kernel/tracing/events/mm_event/mm_event_record/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/lowmemorykiller/lowmemory_kill/enable
+    chmod 0666 /sys/kernel/tracing/events/lowmemorykiller/lowmemory_kill/enable
 
     # disk
     chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
diff --git a/cmds/bugreportz/Android.bp b/cmds/bugreportz/Android.bp
new file mode 100644
index 0000000..924a3a3
--- /dev/null
+++ b/cmds/bugreportz/Android.bp
@@ -0,0 +1,44 @@
+// bugreportz
+// ==========
+cc_binary {
+    name: "bugreportz",
+
+    srcs: [
+        "bugreportz.cpp",
+        "main.cpp",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+    ],
+}
+
+// bugreportz_test
+// ===============
+cc_test {
+    name: "bugreportz_test",
+    test_suites: ["device-tests"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    srcs: [
+        "bugreportz.cpp",
+        "bugreportz_test.cpp",
+    ],
+
+    static_libs: ["libgmock"],
+
+    shared_libs: [
+        "libbase",
+        "libutils",
+    ],
+}
diff --git a/cmds/bugreportz/Android.mk b/cmds/bugreportz/Android.mk
deleted file mode 100644
index 10dda56..0000000
--- a/cmds/bugreportz/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# bugreportz
-# ==========
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-   bugreportz.cpp \
-   main.cpp \
-
-LOCAL_MODULE:= bugreportz
-
-LOCAL_CFLAGS := -Werror -Wall
-
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-
-include $(BUILD_EXECUTABLE)
-
-# bugreportz_test
-# ===============
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := bugreportz_test
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror -Wall
-
-LOCAL_SRC_FILES := \
-    bugreportz.cpp \
-    bugreportz_test.cpp \
-
-LOCAL_STATIC_LIBRARIES := \
-    libgmock \
-
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libutils \
-
-include $(BUILD_NATIVE_TEST)
diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp
new file mode 100644
index 0000000..d91184a
--- /dev/null
+++ b/cmds/cmd/Android.bp
@@ -0,0 +1,18 @@
+cc_binary {
+    name: "cmd",
+
+    srcs: ["cmd.cpp"],
+
+    shared_libs: [
+        "libutils",
+        "liblog",
+        "libselinux",
+        "libbinder",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DXP_UNIX",
+    ],
+}
diff --git a/cmds/cmd/Android.mk b/cmds/cmd/Android.mk
deleted file mode 100644
index 4868555..0000000
--- a/cmds/cmd/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	cmd.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libutils \
-	liblog \
-    libselinux \
-	libbinder
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_C_INCLUDES += \
-    $(JNI_H_INCLUDE)
-
-ifeq ($(TARGET_OS),linux)
-	LOCAL_CFLAGS += -DXP_UNIX
-	#LOCAL_SHARED_LIBRARIES += librt
-endif
-
-LOCAL_MODULE:= cmd
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 260ea4b..849eb44 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -24,10 +24,31 @@
 
 #include "DumpstateInternal.h"
 
+using android::base::StringPrintf;
+
 namespace android {
 namespace os {
 
 namespace {
+
+static binder::Status exception(uint32_t code, const std::string& msg) {
+    MYLOGE("%s (%d) ", msg.c_str(), code);
+    return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
+}
+
+static binder::Status error(uint32_t code, const std::string& msg) {
+    MYLOGE("%s (%d) ", msg.c_str(), code);
+    return binder::Status::fromServiceSpecificError(code, String8(msg.c_str()));
+}
+
+static void* callAndNotify(void* data) {
+    Dumpstate& ds = *static_cast<Dumpstate*>(data);
+    // TODO(111441001): Return status on listener.
+    ds.Run();
+    MYLOGE("Finished Run()\n");
+    return nullptr;
+}
+
 class DumpstateToken : public BnDumpstateToken {};
 }
 
@@ -77,37 +98,59 @@
     return binder::Status::ok();
 }
 
-binder::Status DumpstateService::startBugreport(int, const sp<IDumpstateListener>&,
-                                                const DumpstateOptions&, int32_t* returned_id) {
-    // TODO: fork to handle the bugreport request and return the process id or a request id here.
+binder::Status DumpstateService::startBugreport(int, int bugreport_mode, int32_t* returned_id) {
+    // TODO(111441001): return a request id here.
     *returned_id = -1;
+    MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
+
+    if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL &&
+        bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE &&
+        bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_REMOTE &&
+        bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WEAR &&
+        bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_TELEPHONY &&
+        bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WIFI &&
+        bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_DEFAULT) {
+        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+                         StringPrintf("Invalid bugreport mode: %d", bugreport_mode));
+    }
+
+    std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
+    options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode));
+    ds_.SetOptions(std::move(options));
+
+    pthread_t thread;
+    status_t err = pthread_create(&thread, nullptr, callAndNotify, &ds_);
+    if (err != 0) {
+        return error(err, "Could not create a background thread.");
+    }
     return binder::Status::ok();
 }
 
 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, "bugreport_internal_dir_: %s\n", ds_.bugreport_internal_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/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 131aff3..58095b3 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -41,8 +41,7 @@
                                bool getSectionDetails,
                                sp<IDumpstateToken>* returned_token) override;
 
-    binder::Status startBugreport(int fd, const sp<IDumpstateListener>& listener,
-                                  const DumpstateOptions& options, int32_t* returned_id) override;
+    binder::Status startBugreport(int fd, int bugreport_mode, int32_t* returned_id) override;
 
   private:
     Dumpstate& ds_;
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 600a500..97c8ae2 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -101,13 +101,16 @@
 }
 
 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRoot() {
-    values.account_mode_ = SU_ROOT;
+    if (!PropertiesHelper::IsUnroot()) {
+        values.account_mode_ = SU_ROOT;
+    }
     return *this;
 }
 
 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRootIfAvailable() {
-    if (!PropertiesHelper::IsUserBuild())
-        values.account_mode_ = SU_ROOT;
+    if (!PropertiesHelper::IsUserBuild()) {
+        return AsRoot();
+    }
     return *this;
 }
 
@@ -176,6 +179,7 @@
 
 std::string PropertiesHelper::build_type_ = "";
 int PropertiesHelper::dry_run_ = -1;
+int PropertiesHelper::unroot_ = -1;
 
 bool PropertiesHelper::IsUserBuild() {
     if (build_type_.empty()) {
@@ -191,6 +195,13 @@
     return dry_run_ == 1;
 }
 
+bool PropertiesHelper::IsUnroot() {
+    if (unroot_ == -1) {
+        unroot_ = android::base::GetBoolProperty("dumpstate.unroot", false) ? 1 : 0;
+    }
+    return unroot_ == 1;
+}
+
 int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
     if (fd.get() < 0) {
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index 8342099..d69ffbf 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -97,9 +97,16 @@
       public:
         /* Sets the command to always run, even on `dry-run` mode. */
         CommandOptionsBuilder& Always();
-        /* Sets the command's PrivilegeMode as `SU_ROOT` */
+        /*
+         * Sets the command's PrivilegeMode as `SU_ROOT` unless overridden by system property
+         * 'dumpstate.unroot'.
+         */
         CommandOptionsBuilder& AsRoot();
-        /* If !IsUserBuild(), sets the command's PrivilegeMode as `SU_ROOT` */
+        /*
+         * Runs AsRoot() on userdebug builds. No-op on user builds since 'su' is
+         * not available. This is used for commands that return some useful information even
+         * when run as shell.
+         */
         CommandOptionsBuilder& AsRootIfAvailable();
         /* Sets the command's PrivilegeMode as `DROP_ROOT` */
         CommandOptionsBuilder& DropRoot();
@@ -162,9 +169,17 @@
      */
     static bool IsDryRun();
 
+    /**
+     * Checks whether root availability should be overridden.
+     *
+     * Useful to verify how dumpstate would work in a device with an user build.
+     */
+    static bool IsUnroot();
+
   private:
     static std::string build_type_;
     static int dry_run_;
+    static int unroot_;
 };
 
 /*
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index 0302ea5..6ac17d8 100644
--- a/cmds/dumpstate/README.md
+++ b/cmds/dumpstate/README.md
@@ -26,24 +26,36 @@
 mmm -j frameworks/native/cmds/dumpstate && adb push ${OUT}/system/bin/dumpstate system/bin && adb shell am bug-report
 ```
 
+Make sure that the device is remounted before running the above command.
+* If you're working with `userdebug` variant, you may need to run the following to remount your device:
+
+  ```
+  adb root && adb remount -R && adb wait-for-device && adb root && adb remount
+  ```
+* If you're working with `eng` variant, you may need to run the following to remount your device:
+
+  ```
+  adb root && adb remount
+  ```
+
 ## To build, deploy, and run unit tests
 
-First create `/data/nativetest`:
+First create `/data/nativetest64`:
 
 ```
-adb shell mkdir /data/nativetest
+adb shell mkdir /data/nativetest64
 ```
 
 Then run:
 
 ```
-mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest/dumpstate_test* /data/nativetest && adb shell /data/nativetest/dumpstate_test/dumpstate_test
+mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_test* /data/nativetest64 && adb shell /data/nativetest64/dumpstate_test/dumpstate_test
 ```
 
 And to run just one test (for example, `DumpstateTest.RunCommandNoArgs`):
 
 ```
-mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest/dumpstate_test* /data/nativetest && adb shell /data/nativetest/dumpstate_test/dumpstate_test --gtest_filter=DumpstateTest.RunCommandNoArgs
+mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_test* /data/nativetest64 && adb shell /data/nativetest64/dumpstate_test/dumpstate_test --gtest_filter=DumpstateTest.RunCommandNoArgs
 ```
 
 ## To take quick bugreports
@@ -52,6 +64,12 @@
 adb shell setprop dumpstate.dry_run true
 ```
 
+## To emulate a device with user build
+
+```
+adb shell setprop dumpstate.unroot true
+```
+
 ## To change the `dumpstate` version
 
 ```
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 68a4f21..617eab3 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -39,10 +39,30 @@
     IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener,
                                 boolean getSectionDetails);
 
+    // These modes encapsulate a set of run time options for generating bugreports.
+    // Takes a bugreport without user interference.
+    const int BUGREPORT_MODE_FULL = 0;
+
+    // Interactive bugreport, i.e. triggered by the user.
+    const int BUGREPORT_MODE_INTERACTIVE = 1;
+
+    // Remote bugreport triggered by DevicePolicyManager, for e.g.
+    const int BUGREPORT_MODE_REMOTE = 2;
+
+    // Bugreport triggered on a wear device.
+    const int BUGREPORT_MODE_WEAR = 3;
+
+    // Bugreport limited to only telephony info.
+    const int BUGREPORT_MODE_TELEPHONY = 4;
+
+    // Bugreport limited to only wifi info.
+    const int BUGREPORT_MODE_WIFI = 5;
+
+    // Default mode.
+    const int BUGREPORT_MODE_DEFAULT = 6;
+
     /*
-     * Starts a bugreport in a child process.
-     *
-     * Returns an identifier of the bugreport process running in the background.
+     * Starts a bugreport in the background.
      */
-    int startBugreport(int fd, IDumpstateListener listener, in DumpstateOptions options);
+    int startBugreport(int fd, int bugreportMode);
 }
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 17bb7c3..59a0047 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -82,6 +82,7 @@
 using android::TIMED_OUT;
 using android::UNKNOWN_ERROR;
 using android::Vector;
+using android::base::StringPrintf;
 using android::os::dumpstate::CommandOptions;
 using android::os::dumpstate::DumpFileToFd;
 using android::os::dumpstate::DumpstateSectionReporter;
@@ -121,6 +122,69 @@
 
 // TODO: temporary variables and functions used during C++ refactoring
 static Dumpstate& ds = Dumpstate::GetInstance();
+
+namespace android {
+namespace os {
+namespace {
+
+static int Open(std::string path, int flags, mode_t mode = 0) {
+    int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
+    if (fd == -1) {
+        MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
+    }
+    return fd;
+}
+
+static int OpenForWrite(std::string path) {
+    return Open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+}
+
+static int OpenForRead(std::string path) {
+    return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+}
+
+bool CopyFile(int in_fd, int out_fd) {
+    char buf[4096];
+    ssize_t byte_count;
+    while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
+        if (!android::base::WriteFully(out_fd, buf, byte_count)) {
+            return false;
+        }
+    }
+    return (byte_count != -1);
+}
+
+static bool CopyFileToFd(const std::string& input_file, int out_fd) {
+    MYLOGD("Going to copy bugreport file (%s) to %d\n", ds.path_.c_str(), out_fd);
+
+    // Obtain a handle to the source file.
+    android::base::unique_fd in_fd(OpenForRead(input_file));
+    if (out_fd != -1 && in_fd.get() != -1) {
+        if (CopyFile(in_fd.get(), out_fd)) {
+            return true;
+        }
+        MYLOGE("Failed to copy zip file: %s\n", strerror(errno));
+    }
+    return false;
+}
+
+static bool CopyFileToFile(const std::string& input_file, const std::string& output_file) {
+    if (input_file == output_file) {
+        MYLOGD("Skipping copying bugreport file since the destination is the same (%s)\n",
+               output_file.c_str());
+        return false;
+    }
+
+    MYLOGD("Going to copy bugreport file (%s) to %s\n", input_file.c_str(), output_file.c_str());
+    android::base::unique_fd out_fd(OpenForWrite(output_file));
+    return CopyFileToFd(input_file, out_fd.get());
+}
+
+}  // namespace
+}  // namespace os
+}  // namespace android
+
 static int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
                       const CommandOptions& options = CommandOptions::DEFAULT) {
     return ds.RunCommand(title, fullCommand, options);
@@ -137,8 +201,6 @@
 // Relative directory (inside the zip) for all files copied as-is into the bugreport.
 static const std::string ZIP_ROOT_DIR = "FS";
 
-// Must be hardcoded because dumpstate HAL implementation need SELinux access to it
-static const std::string kDumpstateBoardPath = "/bugreports/";
 static const std::string kProtoPath = "proto/";
 static const std::string kProtoExt = ".proto";
 static const std::string kDumpstateBoardFiles[] = {
@@ -682,7 +744,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");
 }
 
@@ -1100,7 +1162,7 @@
     }
 }
 
-// Runs dumpsys on services that must dump first and and will take less than 100ms to dump.
+// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
 static void RunDumpsysCritical() {
     RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
                    /* timeout= */ 5s, /* service_timeout= */ 500ms);
@@ -1145,7 +1207,7 @@
                                 return !isalnum(c) &&
                                     std::string("@-_:.").find(c) == std::string::npos;
                             }, '_');
-            const std::string path = kDumpstateBoardPath + "lshal_debug_" + cleanName;
+            const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
 
             {
                 auto fd = android::base::unique_fd(
@@ -1523,7 +1585,8 @@
     std::vector<std::string> paths;
     std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
     for (int i = 0; i < NUM_OF_DUMPS; i++) {
-        paths.emplace_back(kDumpstateBoardPath + kDumpstateBoardFiles[i]);
+        paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
+                                        kDumpstateBoardFiles[i].c_str()));
         remover.emplace_back(android::base::make_scope_guard(std::bind(
             [](std::string path) {
                 if (remove(path.c_str()) != 0 && errno != ENOENT) {
@@ -1623,7 +1686,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 +1706,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() {
@@ -1681,7 +1744,8 @@
         MYLOGE("Failed to add dumpstate log to .zip file\n");
         return false;
     }
-    // ... and re-opens it for further logging.
+    // TODO: Should truncate the existing file.
+    // ... and re-open it for further logging.
     redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
     fprintf(stderr, "\n");
 
@@ -1764,18 +1828,31 @@
     // clang-format on
 }
 
+static void MaybeResolveSymlink(std::string* path) {
+    std::string resolved_path;
+    if (android::base::Readlink(*path, &resolved_path)) {
+        *path = resolved_path;
+    }
+}
+
 /*
  * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
  * 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());
+    MaybeResolveSymlink(&ds.bugreport_internal_dir_);
+
+    std::string base_name_part1 = "bugreport";
+    if (!ds.options_->use_outfile.empty()) {
+        ds.bugreport_dir_ = dirname(ds.options_->use_outfile.c_str());
+        base_name_part1 = basename(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_ =
+        StringPrintf("%s-%s-%s", base_name_part1.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,29 +1860,32 @@
         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");
     ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
 
+    std::string destination = ds.options_->fd != -1 ? StringPrintf("[fd:%d]", ds.options_->fd)
+                                                    : ds.bugreport_dir_.c_str();
     MYLOGD(
         "Bugreport dir: %s\n"
+        "Internal Bugreport dir: %s\n"
         "Base name: %s\n"
         "Suffix: %s\n"
         "Log path: %s\n"
         "Temporary path: %s\n"
         "Screenshot path: %s\n",
-        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());
+        destination.c_str(), ds.bugreport_internal_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 +1904,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,13 +1932,13 @@
     }
 
     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;
         } else {
             do_text_file = false;
-            // Since zip file is already created, it needs to be renamed.
+            // If the user has changed the suffix, we need to change the zip file name.
             std::string new_path = ds.GetPath(".zip");
             if (ds.path_ != new_path) {
                 MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
@@ -1870,6 +1949,19 @@
                     ds.path_ = new_path;
                 }
             }
+            // The zip file lives in an internal directory. Copy it over to output.
+            bool copy_succeeded = false;
+            if (ds.options_->fd != -1) {
+                copy_succeeded = android::os::CopyFileToFd(ds.path_, ds.options_->fd);
+            } else {
+                ds.final_path_ = ds.GetPath(ds.bugreport_dir_, ".zip");
+                copy_succeeded = android::os::CopyFileToFile(ds.path_, ds.final_path_);
+            }
+            if (copy_succeeded) {
+                if (remove(ds.path_.c_str())) {
+                    MYLOGE("remove(%s): %s", ds.path_.c_str(), strerror(errno));
+                }
+            }
         }
     }
     if (do_text_file) {
@@ -1880,7 +1972,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,9 +1986,9 @@
 
 /* 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());
+    // TODO(b/111441001): use callback instead of broadcast.
+    if (!ds.final_path_.empty()) {
+        MYLOGI("Final bugreport path: %s\n", ds.final_path_.c_str());
         // clang-format off
 
         std::vector<std::string> am_args = {
@@ -1904,29 +1996,29 @@
              "--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.BUGREPORT", ds.path_,
+             "--es", "android.intent.extra.BUGREPORT", ds.final_path_,
              "--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_));
+            am_args.push_back(SHA256_file_hash(ds.final_path_));
             SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
         } else {
             SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
@@ -1936,30 +2028,178 @@
     }
 }
 
-int Dumpstate::ParseCommandlineOptions(int argc, char* argv[]) {
-    int ret = -1;  // success
+static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
+    switch (mode) {
+        case Dumpstate::BugreportMode::BUGREPORT_FULL:
+            return "BUGREPORT_FULL";
+        case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
+            return "BUGREPORT_INTERACTIVE";
+        case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
+            return "BUGREPORT_REMOTE";
+        case Dumpstate::BugreportMode::BUGREPORT_WEAR:
+            return "BUGREPORT_WEAR";
+        case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
+            return "BUGREPORT_TELEPHONY";
+        case Dumpstate::BugreportMode::BUGREPORT_WIFI:
+            return "BUGREPORT_WIFI";
+        case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
+            return "BUGREPORT_DEFAULT";
+    }
+}
+
+static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
+    options->extra_options = ModeToString(mode);
+    switch (mode) {
+        case Dumpstate::BugreportMode::BUGREPORT_FULL:
+            options->do_broadcast = true;
+            options->do_fb = true;
+            break;
+        case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
+            // 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;
+            options->do_broadcast = true;
+            break;
+        case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
+            options->do_vibrate = false;
+            options->is_remote_mode = true;
+            options->do_fb = false;
+            options->do_broadcast = true;
+            break;
+        case Dumpstate::BugreportMode::BUGREPORT_WEAR:
+            options->do_start_service = true;
+            options->do_progress_updates = true;
+            options->do_zip_file = true;
+            options->do_fb = true;
+            options->do_broadcast = true;
+            break;
+        case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
+            options->telephony_only = true;
+            options->do_fb = true;
+            options->do_broadcast = true;
+            break;
+        case Dumpstate::BugreportMode::BUGREPORT_WIFI:
+            options->wifi_only = true;
+            options->do_zip_file = true;
+            options->do_fb = true;
+            options->do_broadcast = true;
+            break;
+        case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
+            break;
+    }
+}
+
+static Dumpstate::BugreportMode getBugreportModeFromProperty() {
+    // If the system property is not set, it's assumed to be a default bugreport.
+    Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
+
+    std::string 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") {
+            mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
+        } else if (extra_options == "bugreportfull") {
+            mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
+        } else if (extra_options == "bugreportremote") {
+            mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
+        } else if (extra_options == "bugreportwear") {
+            mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
+        } else if (extra_options == "bugreporttelephony") {
+            mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
+        } else if (extra_options == "bugreportwifi") {
+            mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
+        } else {
+            MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
+        }
+        // Reset the property
+        android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
+    }
+    return mode;
+}
+
+// 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) {
+    Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
+    SetOptionsFromMode(mode, 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->notification_description =
+            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());
+    }
+}
+
+static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
+    MYLOGI("do_zip_file: %d\n", options.do_zip_file);
+    MYLOGI("do_add_date: %d\n", options.do_add_date);
+    MYLOGI("do_vibrate: %d\n", options.do_vibrate);
+    MYLOGI("use_socket: %d\n", options.use_socket);
+    MYLOGI("use_control_socket: %d\n", options.use_control_socket);
+    MYLOGI("do_fb: %d\n", options.do_fb);
+    MYLOGI("do_broadcast: %d\n", options.do_broadcast);
+    MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
+    MYLOGI("show_header_only: %d\n", options.show_header_only);
+    MYLOGI("do_start_service: %d\n", options.do_start_service);
+    MYLOGI("telephony_only: %d\n", options.telephony_only);
+    MYLOGI("wifi_only: %d\n", options.wifi_only);
+    MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
+    MYLOGI("fd: %d\n", options.fd);
+    MYLOGI("use_outfile: %s\n", options.use_outfile.c_str());
+    MYLOGI("extra_options: %s\n", options.extra_options.c_str());
+    MYLOGI("args: %s\n", options.args.c_str());
+    MYLOGI("notification_title: %s\n", options.notification_title.c_str());
+    MYLOGI("notification_description: %s\n", options.notification_description.c_str());
+}
+
+void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode) {
+    // In the new API world, date is always added; output is always a zip file.
+    // TODO(111441001): remove these options once they are obsolete.
+    do_add_date = true;
+    do_zip_file = true;
+
+    // STOPSHIP b/111441001: Remove hardcoded output file path; accept fd.
+    use_outfile = "/data/user_de/0/com.android.shell/files/bugreports/bugreport";
+
+    extra_options = ModeToString(bugreport_mode);
+    SetOptionsFromMode(bugreport_mode, this);
+}
+
+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 +2207,75 @@
 
     // 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 (fd != -1 && !do_zip_file) {
         return false;
     }
 
-    if (options_.use_control_socket && !options_.do_zip_file) {
+    bool has_out_file_options = !use_outfile.empty() || fd != -1;
+    if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) &&
+        !has_out_file_options) {
         return false;
     }
 
-    if (ds.update_progress_ && !options_.do_broadcast) {
+    if (use_control_socket && !do_zip_file) {
         return false;
     }
 
-    if (options_.is_remote_mode && (ds.update_progress_ || !options_.do_broadcast ||
-                                    !options_.do_zip_file || !options_.do_add_date)) {
+    if (do_progress_updates && !do_broadcast) {
+        return false;
+    }
+
+    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[]) {
+void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
+    options_ = std::move(options);
+}
+
+/*
+ * Dumps relevant information to a bugreport based on the given options.
+ *
+ * The bugreport can be dumped to a file or streamed to a socket.
+ *
+ * How dumping to file works:
+ * stdout is redirected to a temporary file. This will later become the main bugreport entry.
+ * stderr is redirected a log file.
+ *
+ * The temporary bugreport is then populated via printfs, dumping contents of files and
+ * output of commands to stdout.
+ *
+ * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
+ * text file.
+ *
+ * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
+ * gets added to the archive.
+ *
+ * Bugreports are first generated in a local directory and later copied to the caller's fd or
+ * directory.
+ */
+Dumpstate::RunStatus Dumpstate::Run() {
+    LogDumpOptions(*options_);
+    if (!options_->ValidateOptions()) {
+        MYLOGE("Invalid options specified\n");
+        return RunStatus::INVALID_INPUT;
+    }
     /* set as high priority, and protect from OOM killer */
     setpriority(PRIO_PROCESS, 0, -20);
 
@@ -2064,52 +2292,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", bugreport_internal_dir_.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 +2339,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 +2387,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));
         }
     }
@@ -2193,20 +2411,25 @@
     int dup_stdout_fd;
     int dup_stderr_fd;
     if (is_redirecting) {
+        // Redirect stderr to log_path_ for debugging.
         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));
         }
+
+        // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
+        // moved into zip file later, if zipping.
         TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
+        // TODO: why not write to a file instead of stdout to overcome this problem?
         /* 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 +2439,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 +2460,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 +2473,52 @@
     }
 
     /* 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 binary. */
+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) {
+        ds.SetOptions(std::move(options));
+        status = ds.Run();
+    }
+
+    switch (status) {
+        case Dumpstate::RunStatus::OK:
+            return 0;
+            // TODO(b/111441001): Exit directly in the following cases.
+        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..ee952d9 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -27,6 +27,7 @@
 
 #include <android-base/macros.h>
 #include <android-base/unique_fd.h>
+#include <android/os/IDumpstate.h>
 #include <android/os/IDumpstateListener.h>
 #include <utils/StrongPointer.h>
 #include <ziparchive/zip_writer.h>
@@ -42,6 +43,9 @@
 // TODO: and then remove explicitly android::os::dumpstate:: prefixes
 namespace android {
 namespace os {
+
+struct DumpstateOptions;
+
 namespace dumpstate {
 
 class DumpstateTest;
@@ -138,7 +142,7 @@
     float growth_factor_;
     int32_t n_runs_;
     int32_t average_max_;
-    const std::string& path_;
+    std::string path_;
 };
 
 /*
@@ -160,6 +164,11 @@
 static std::string VERSION_DEFAULT = "default";
 
 /*
+ * Directory used by Dumpstate binary to keep its local files.
+ */
+static const std::string DUMPSTATE_DIRECTORY = "/bugreports";
+
+/*
  * Structure that contains the information of an open dump file.
  */
 struct DumpData {
@@ -183,6 +192,19 @@
     friend class DumpstateTest;
 
   public:
+    enum RunStatus { OK, HELP, INVALID_INPUT, ERROR };
+
+    // The mode under which the bugreport should be run. Each mode encapsulates a few options.
+    enum BugreportMode {
+        BUGREPORT_FULL = android::os::IDumpstate::BUGREPORT_MODE_FULL,
+        BUGREPORT_INTERACTIVE = android::os::IDumpstate::BUGREPORT_MODE_INTERACTIVE,
+        BUGREPORT_REMOTE = android::os::IDumpstate::BUGREPORT_MODE_REMOTE,
+        BUGREPORT_WEAR = android::os::IDumpstate::BUGREPORT_MODE_WEAR,
+        BUGREPORT_TELEPHONY = android::os::IDumpstate::BUGREPORT_MODE_TELEPHONY,
+        BUGREPORT_WIFI = android::os::IDumpstate::BUGREPORT_MODE_WIFI,
+        BUGREPORT_DEFAULT = android::os::IDumpstate::BUGREPORT_MODE_DEFAULT
+    };
+
     static android::os::dumpstate::CommandOptions DEFAULT_DUMPSYS;
 
     static Dumpstate& GetInstance();
@@ -245,7 +267,7 @@
                                         std::chrono::milliseconds timeout);
 
     /*
-     * Adds a text entry entry to the existing zip file.
+     * Adds a text entry to the existing zip file.
      */
     bool AddTextZipEntry(const std::string& entry_name, const std::string& content);
 
@@ -284,28 +306,24 @@
      */
     bool FinishZipFile();
 
-    /* Gets the path of a bugreport file with the given suffix. */
+    /* Constructs a full path inside directory with file name formatted using the given suffix. */
+    std::string GetPath(const std::string& directory, const std::string& suffix) const;
+
+    /* Constructs a full path inside bugreport_internal_dir_ with file name formatted using the
+     * given suffix. */
     std::string GetPath(const std::string& suffix) const;
 
     /* 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. */
+    RunStatus Run();
 
-    /* Returns true if the options set so far are consistent. */
-    bool ValidateOptions();
+    /* Sets runtime options. */
+    void SetOptions(std::unique_ptr<DumpOptions> options);
 
-    // TODO: add update_progress_ & other options from DumpState.
     /*
      * Structure to hold options that determine the behavior of dumpstate.
      */
@@ -322,7 +340,30 @@
         bool do_start_service = false;
         bool telephony_only = false;
         bool wifi_only = false;
+        // Whether progress updates should be published.
+        bool do_progress_updates = false;
+        // File descriptor to output zip file. -1 indicates not set. Takes precedence over
+        // use_outfile.
+        int fd = -1;
+        // Partial path to output file.
         std::string use_outfile;
+        // TODO: rename to MODE.
+        // 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[]);
+
+        /* Initializes options from the requested mode. */
+        void Initialize(BugreportMode bugreport_mode);
+
+        /* Returns true if the options set so far are consistent. */
+        bool ValidateOptions() const;
     };
 
     // TODO: initialize fields on constructor
@@ -333,10 +374,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,18 +394,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_;
-
-    // Full path of the temporary file containing the screenshot (when requested).
-    std::string screenshot_path_;
-
     time_t now_;
 
     // Base name (without suffix or extensions) of the bugreport files, typically
@@ -378,15 +404,30 @@
     // `-d`), but it could be changed by the user..
     std::string name_;
 
-    // Full path of the temporary file containing the bugreport.
+    std::string bugreport_internal_dir_ = DUMPSTATE_DIRECTORY;
+
+    // Full path of the temporary file containing the bugreport, inside bugreport_internal_dir_.
+    // At the very end this file is pulled into the zip file.
     std::string tmp_path_;
 
-    // Full path of the file containing the dumpstate logs.
+    // Full path of the file containing the dumpstate logs, inside bugreport_internal_dir_.
+    // This is useful for debugging.
     std::string log_path_;
 
-    // Pointer to the actual path, be it zip or text.
+    // Full path of the bugreport file, be it zip or text, inside bugreport_internal_dir_.
     std::string path_;
 
+    // TODO: If temporary this should be removed at the end.
+    // Full path of the temporary file containing the screenshot (when requested).
+    std::string screenshot_path_;
+
+    // TODO(b/111441001): remove when obsolete.
+    // Full path of the final zip file inside the caller-specified directory, if available.
+    std::string final_path_;
+
+    // The caller-specified directory, if available.
+    std::string bugreport_dir_;
+
     // Pointer to the zipped file.
     std::unique_ptr<FILE, int (*)(FILE*)> zip_file{nullptr, fclose};
 
@@ -398,10 +439,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..fcf9371 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -36,6 +36,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <cutils/properties.h>
 
 namespace android {
 namespace os {
@@ -85,6 +86,10 @@
         PropertiesHelper::build_type_ = build_type;
     }
 
+    void SetUnroot(bool unroot) const {
+        PropertiesHelper::unroot_ = unroot;
+    }
+
     bool IsStandalone() const {
         return calls_ == 1;
     }
@@ -137,6 +142,463 @@
     }
 };
 
+class DumpOptionsTest : public Test {
+  public:
+    virtual ~DumpOptionsTest() {
+    }
+    virtual void SetUp() {
+        options_ = Dumpstate::DumpOptions();
+    }
+    void TearDown() {
+        // Reset the property
+        property_set("dumpstate.options", "");
+    }
+    Dumpstate::DumpOptions options_;
+};
+
+TEST_F(DumpOptionsTest, InitializeNone) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate")
+    };
+    // clang-format on
+
+    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, InitializeAdbBugreport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstatez"),
+        const_cast<char*>("-S"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-z"),
+        const_cast<char*>("-o abc"),
+    };
+    // 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);
+    EXPECT_TRUE(options_.use_control_socket);
+    EXPECT_EQ(" abc", std::string(options_.use_outfile));
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_fb);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.do_broadcast);
+    EXPECT_FALSE(options_.use_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        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_.use_socket);
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_EQ("", options_.use_outfile);
+    EXPECT_FALSE(options_.do_add_date);
+    EXPECT_FALSE(options_.do_zip_file);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    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, InitializeFullBugReport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+        const_cast<char*>("-o abc"),
+    };
+    // clang-format on
+    property_set("dumpstate.options", "bugreportfull");
+
+    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_fb);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.do_broadcast);
+    EXPECT_EQ(" abc", std::string(options_.use_outfile));
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.do_start_service);
+}
+
+TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+        const_cast<char*>("-o abc"),
+    };
+    // clang-format on
+
+    property_set("dumpstate.options", "bugreportplus");
+
+    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_broadcast);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.do_progress_updates);
+    EXPECT_TRUE(options_.do_start_service);
+    EXPECT_FALSE(options_.do_fb);
+    EXPECT_EQ(" abc", std::string(options_.use_outfile));
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.use_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeRemoteBugReport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+        const_cast<char*>("-o abc"),
+    };
+    // clang-format on
+
+    property_set("dumpstate.options", "bugreportremote");
+
+    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_broadcast);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.do_vibrate);
+    EXPECT_FALSE(options_.do_fb);
+    EXPECT_EQ(" abc", std::string(options_.use_outfile));
+
+    // Other options retain default values
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.use_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeWearBugReport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+        const_cast<char*>("-o abc"),
+    };
+    // clang-format on
+
+    property_set("dumpstate.options", "bugreportwear");
+
+    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_fb);
+    EXPECT_TRUE(options_.do_broadcast);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.do_progress_updates);
+    EXPECT_TRUE(options_.do_start_service);
+    EXPECT_EQ(" abc", std::string(options_.use_outfile));
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.use_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+        const_cast<char*>("-o abc"),
+    };
+    // clang-format on
+
+    property_set("dumpstate.options", "bugreporttelephony");
+
+    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_fb);
+    EXPECT_TRUE(options_.do_broadcast);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.telephony_only);
+    EXPECT_EQ(" abc", std::string(options_.use_outfile));
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.use_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeWifiBugReport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+        const_cast<char*>("-o abc"),
+    };
+    // clang-format on
+
+    property_set("dumpstate.options", "bugreportwifi");
+
+    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_fb);
+    EXPECT_TRUE(options_.do_broadcast);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.wifi_only);
+    EXPECT_EQ(" abc", std::string(options_.use_outfile));
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.use_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeDefaultBugReport) {
+    // default: commandline options are not overridden
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+        const_cast<char*>("-o abc"),
+    };
+    // clang-format on
+
+    property_set("dumpstate.options", "");
+
+    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_fb);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.do_broadcast);
+    EXPECT_EQ(" abc", std::string(options_.use_outfile));
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.wifi_only);
+}
+
+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 +606,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 +632,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 +665,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("", {}));
 }
@@ -633,6 +943,32 @@
     EXPECT_THAT(err, StrEq("stderr\n"));
 }
 
+TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild_withUnroot) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it might cause other tests to fail after dropping
+        // to Shell - need to refactor tests to avoid this problem)
+        MYLOGE(
+            "Skipping DumpstateTest.RunCommandAsRootNonUserBuild_withUnroot() "
+            "on test suite\n")
+        return;
+    }
+    if (PropertiesHelper::IsUserBuild()) {
+        ALOGI("Skipping RunCommandAsRootNonUserBuild_withUnroot on user builds\n");
+        return;
+    }
+
+    // Same test as above, but with unroot property set, which will override su availability.
+    SetUnroot(true);
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRoot().Build()));
+
+    // AsRoot is ineffective.
+    EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+    EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
+}
+
 TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnUserBuild) {
     if (!IsStandalone()) {
         // TODO: temporarily disabled because it might cause other tests to fail after dropping
@@ -675,6 +1011,32 @@
     EXPECT_THAT(err, StrEq("stderr\n"));
 }
 
+TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild_withUnroot) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it might cause other tests to fail after dropping
+        // to Shell - need to refactor tests to avoid this problem)
+        MYLOGE(
+            "Skipping DumpstateTest.RunCommandAsRootIfAvailableOnDebugBuild_withUnroot() "
+            "on test suite\n")
+        return;
+    }
+    if (PropertiesHelper::IsUserBuild()) {
+        ALOGI("Skipping RunCommandAsRootIfAvailableOnDebugBuild_withUnroot on user builds\n");
+        return;
+    }
+    // Same test as above, but with unroot property set, which will override su availability.
+    SetUnroot(true);
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+    // It's a userdebug build, so "su root" should be available, but unroot=true overrides it.
+    EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
 TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) {
     EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
     EXPECT_THAT(out,
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 77f09b7..d97ffbf 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -82,8 +82,12 @@
 
 CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
 
+// TODO(111441001): Default DumpOptions to sensible values.
 Dumpstate::Dumpstate(const std::string& version)
-    : pid_(getpid()), version_(version), now_(time(nullptr)) {
+    : pid_(getpid()),
+      options_(new Dumpstate::DumpOptions()),
+      version_(version),
+      now_(time(nullptr)) {
 }
 
 Dumpstate& Dumpstate::GetInstance() {
@@ -225,7 +229,11 @@
 }
 
 std::string Dumpstate::GetPath(const std::string& suffix) const {
-    return android::base::StringPrintf("%s/%s-%s%s", bugreport_dir_.c_str(), base_name_.c_str(),
+    return GetPath(bugreport_internal_dir_, suffix);
+}
+
+std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
+    return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
                                        name_.c_str(), suffix.c_str());
 }
 
@@ -916,7 +924,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/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 5412d4d..8fbea8a 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -389,7 +389,7 @@
         auto time_left_ms = [end]() {
             auto now = std::chrono::steady_clock::now();
             auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
-            return std::max(diff.count(), 0ll);
+            return std::max(diff.count(), 0LL);
         };
 
         int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
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/CacheItem.cpp b/cmds/installd/CacheItem.cpp
index 515f915..e29ff4c 100644
--- a/cmds/installd/CacheItem.cpp
+++ b/cmds/installd/CacheItem.cpp
@@ -73,7 +73,7 @@
         FTS *fts;
         FTSENT *p;
         char *argv[] = { (char*) path.c_str(), nullptr };
-        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
             PLOG(WARNING) << "Failed to fts_open " << path;
             return -1;
         }
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index ea0cd9e..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 {
@@ -103,7 +99,7 @@
     FTS *fts;
     FTSENT *p;
     char *argv[] = { (char*) path.c_str(), nullptr };
-    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
         PLOG(WARNING) << "Failed to fts_open " << path;
         return;
     }
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 e336232..2439dff 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -31,7 +31,6 @@
 #include <sys/file.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
-#include <sys/quota.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
@@ -64,6 +63,7 @@
 
 #include "CacheTracker.h"
 #include "MatchExtensionGen.h"
+#include "QuotaUtils.h"
 
 #ifndef LOG_TAG
 #define LOG_TAG "installd"
@@ -77,7 +77,6 @@
 
 static constexpr const char* kCpPath = "/system/bin/cp";
 static constexpr const char* kXattrDefault = "user.default";
-static constexpr const char* kPropHasReserved = "vold.has_reserved";
 
 static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
 
@@ -267,11 +266,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;
-        }
     }
 
     {
@@ -352,55 +346,6 @@
     return 0;
 }
 
-/**
- * Ensure that we have a hard-limit quota to protect against abusive apps;
- * they should never use more than 90% of blocks or 50% of inodes.
- */
-static int prepare_app_quota(const std::unique_ptr<std::string>& uuid ATTRIBUTE_UNUSED,
-        const std::string& device, uid_t uid) {
-    // Skip when reserved blocks are protecting us against abusive apps
-    if (android::base::GetBoolProperty(kPropHasReserved, false)) return 0;
-    // Skip when device no quotas present
-    if (device.empty()) return 0;
-
-    struct dqblk dq;
-    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
-            reinterpret_cast<char*>(&dq)) != 0) {
-        PLOG(WARNING) << "Failed to find quota for " << uid;
-        return -1;
-    }
-
-#if APPLY_HARD_QUOTAS
-    if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) {
-        auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
-        struct statvfs stat;
-        if (statvfs(path.c_str(), &stat) != 0) {
-            PLOG(WARNING) << "Failed to statvfs " << path;
-            return -1;
-        }
-
-        dq.dqb_valid = QIF_LIMITS;
-        dq.dqb_bhardlimit =
-            (((static_cast<uint64_t>(stat.f_blocks) * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
-        dq.dqb_ihardlimit = (stat.f_files / 2);
-        if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            PLOG(WARNING) << "Failed to set hard quota for " << uid;
-            return -1;
-        } else {
-            LOG(DEBUG) << "Applied hard quotas for " << uid;
-            return 0;
-        }
-    } else {
-        // Hard quota already set; assume it's reasonable
-        return 0;
-    }
-#else
-    // Hard quotas disabled
-    return 0;
-#endif
-}
-
 static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
     if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
         return true;
@@ -515,10 +460,6 @@
             return error("Failed to restorecon " + path);
         }
 
-        if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) {
-            return error("Failed to set hard quota " + path);
-        }
-
         if (!prepare_app_profile_dir(packageName, appId, userId)) {
             return error("Failed to prepare profiles for " + packageName);
         }
@@ -715,7 +656,7 @@
         auto ce_path = create_data_user_ce_path(uuid_, user);
         auto de_path = create_data_user_de_path(uuid_, user);
         char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(), nullptr };
-        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
             return error("Failed to fts_open");
         }
         while ((p = fts_read(fts)) != nullptr) {
@@ -840,7 +781,7 @@
         };
 
         LOG(DEBUG) << "Copying " << from << " to " << to;
-        int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+        int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
         if (rc != 0) {
             res = error(rc, "Failed copying " + from + " to " + to);
             goto fail;
@@ -886,7 +827,7 @@
             argv[7] = (char*) to.c_str();
 
             LOG(DEBUG) << "Copying " << from << " to " << to;
-            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
             if (rc != 0) {
                 res = error(rc, "Failed copying " + from + " to " + to);
                 goto fail;
@@ -899,7 +840,7 @@
             argv[7] = (char*) to.c_str();
 
             LOG(DEBUG) << "Copying " << from << " to " << to;
-            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
             if (rc != 0) {
                 res = error(rc, "Failed copying " + from + " to " + to);
                 goto fail;
@@ -922,20 +863,20 @@
     // Nuke everything we might have already copied
     {
         auto to = create_data_app_package_path(to_uuid, data_app_name);
-        if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+        if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
             LOG(WARNING) << "Failed to rollback " << to;
         }
     }
     for (auto user : users) {
         {
             auto to = create_data_user_de_package_path(to_uuid, user, package_name);
-            if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
                 LOG(WARNING) << "Failed to rollback " << to;
             }
         }
         {
             auto to = create_data_user_ce_package_path(to_uuid, user, package_name);
-            if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
                 LOG(WARNING) << "Failed to rollback " << to;
             }
         }
@@ -958,13 +899,6 @@
         }
     }
 
-    // Data under /data/media doesn't have an app, but we still want
-    // to limit it to prevent abuse.
-    if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid),
-            multiuser_get_uid(userId, AID_MEDIA_RW))) {
-        return error("Failed to set hard quota for media_rw");
-    }
-
     return ok();
 }
 
@@ -1011,9 +945,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);
@@ -1045,10 +979,10 @@
             auto media_path = findDataMediaPath(uuid, user) + "/Android/data/";
             char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(),
                     (char*) media_path.c_str(), nullptr };
-            if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+            if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
                 return error("Failed to fts_open");
             }
-            while ((p = fts_read(fts)) != NULL) {
+            while ((p = fts_read(fts)) != nullptr) {
                 if (p->fts_info == FTS_D && p->fts_level == 1) {
                     uid_t uid = p->fts_statp->st_uid;
                     if (multiuser_get_app_id(uid) == AID_MEDIA_RW) {
@@ -1060,7 +994,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);
@@ -1225,53 +1159,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;
             }
         }
     }
@@ -1279,32 +1186,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;
             }
         }
     }
@@ -1398,11 +1289,11 @@
     FTS *fts;
     FTSENT *p;
     char *argv[] = { (char*) path.c_str(), nullptr };
-    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
         PLOG(ERROR) << "Failed to fts_open " << path;
         return;
     }
-    while ((p = fts_read(fts)) != NULL) {
+    while ((p = fts_read(fts)) != nullptr) {
         p->fts_number = p->fts_parent->fts_number;
         switch (p->fts_info) {
         case FTS_D:
@@ -1468,10 +1359,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;
     }
 
@@ -1491,7 +1382,7 @@
         ATRACE_END();
 
         ATRACE_BEGIN("quota");
-        collectQuotaStats(device, userId, appId, &stats, &extStats);
+        collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
         ATRACE_END();
     } else {
         ATRACE_BEGIN("code");
@@ -1574,27 +1465,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();
 
@@ -1620,16 +1503,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();
 
@@ -1646,7 +1521,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
@@ -1728,6 +1603,7 @@
     LOG(INFO) << "Measuring external " << userId;
 #endif
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
     int64_t totalSize = 0;
@@ -1737,58 +1613,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();
 
@@ -1797,7 +1648,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;
@@ -1808,10 +1659,10 @@
         FTSENT *p;
         auto path = create_data_media_path(uuid_, userId);
         char *argv[] = { (char*) path.c_str(), nullptr };
-        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
             return error("Failed to fts_open " + path);
         }
-        while ((p = fts_read(fts)) != NULL) {
+        while ((p = fts_read(fts)) != nullptr) {
             char* ext;
             int64_t size = (p->fts_statp->st_blocks * 512);
             switch (p->fts_info) {
@@ -2041,7 +1892,7 @@
         }
     } else {
         if (S_ISDIR(libStat.st_mode)) {
-            if (delete_dir_contents(libsymlink, 1, NULL) < 0) {
+            if (delete_dir_contents(libsymlink, 1, nullptr) < 0) {
                 res = error("Failed to delete " + _libsymlink);
                 goto out;
             }
@@ -2083,14 +1934,14 @@
 static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
 {
     execl(kIdMapPath, kIdMapPath, "--fd", target_apk, overlay_apk,
-            StringPrintf("%d", idmap_fd).c_str(), (char*)NULL);
+            StringPrintf("%d", idmap_fd).c_str(), (char*)nullptr);
     PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
 }
 
 static void run_verify_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
 {
     execl(kIdMapPath, kIdMapPath, "--verify", target_apk, overlay_apk,
-            StringPrintf("%d", idmap_fd).c_str(), (char*)NULL);
+            StringPrintf("%d", idmap_fd).c_str(), (char*)nullptr);
     PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
 }
 
@@ -2141,7 +1992,7 @@
 static int flatten_path(const char *prefix, const char *suffix,
         const char *overlay_path, char *idmap_path, size_t N)
 {
-    if (overlay_path == NULL || idmap_path == NULL) {
+    if (overlay_path == nullptr || idmap_path == nullptr) {
         return -1;
     }
     const size_t len_overlay_path = strlen(overlay_path);
@@ -2482,7 +2333,7 @@
                      std::to_string(shmSize));
     }
     auto data = std::unique_ptr<void, std::function<void (void *)>>(
-        mmap(NULL, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
+        mmap(nullptr, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
         [contentSize] (void* ptr) {
           if (ptr != MAP_FAILED) {
             munmap(ptr, contentSize);
@@ -2585,7 +2436,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()) {
@@ -2606,32 +2462,6 @@
             mStorageMounts[source] = target;
         }
 #endif
-
-#if !BYPASS_QUOTA
-        if (source.compare(0, 11, "/dev/block/") == 0) {
-            struct dqblk dq;
-            if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
-                    reinterpret_cast<char*>(&dq)) == 0) {
-                LOG(DEBUG) << "Found quota mount " << source << " at " << target;
-                mQuotaReverseMounts[target] = source;
-
-                // ext4 only enables DQUOT_USAGE_ENABLED by default, so we
-                // need to kick it again to enable DQUOT_LIMITS_ENABLED. We
-                // only need hard limits enabled when we're not being protected
-                // by reserved blocks.
-                if (!android::base::GetBoolProperty(kPropHasReserved, false)) {
-                    if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1,
-                            nullptr) != 0 && errno != EBUSY) {
-                        PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
-                    }
-                    if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1,
-                            nullptr) != 0 && errno != EBUSY) {
-                        PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
-                    }
-                }
-            }
-        }
-#endif
     }
     return ok();
 }
@@ -2649,16 +2479,10 @@
     return StringPrintf("%s/%u", resolved.c_str(), userid);
 }
 
-std::string InstalldNativeService::findQuotaDeviceForUuid(
-        const std::unique_ptr<std::string>& uuid) {
-    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
-    auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
-    return mQuotaReverseMounts[path];
-}
-
 binder::Status InstalldNativeService::isQuotaSupported(
-        const std::unique_ptr<std::string>& volumeUuid, bool* _aidl_return) {
-    *_aidl_return = !findQuotaDeviceForUuid(volumeUuid).empty();
+        const std::unique_ptr<std::string>& uuid, bool* _aidl_return) {
+    auto uuidString = uuid ? *uuid : "";
+    *_aidl_return = IsQuotaSupported(uuidString);
     return ok();
 }
 
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index cebd3f9..367f2c1 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -150,14 +150,11 @@
 
     /* Map of all storage mounts from source to target */
     std::unordered_map<std::string, std::string> mStorageMounts;
-    /* Map of all quota mounts from target to source */
-    std::unordered_map<std::string, std::string> mQuotaReverseMounts;
 
     /* Map from UID to cache quota size */
     std::unordered_map<uid_t, int64_t> mCacheQuotas;
 
     std::string findDataMediaPath(const std::unique_ptr<std::string>& uuid, userid_t userid);
-    std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
 };
 
 }  // namespace installd
diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS
index 50440f1..5d4f176 100644
--- a/cmds/installd/OWNERS
+++ b/cmds/installd/OWNERS
@@ -1,7 +1,8 @@
 set noparent
 
-calin@google.com
 agampe@google.com
+calin@google.com
 jsharkey@android.com
-toddke@google.com
+mathieuc@google.com
 ngeoffray@google.com
+toddke@google.com
diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp
new file mode 100644
index 0000000..b238dd3
--- /dev/null
+++ b/cmds/installd/QuotaUtils.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "QuotaUtils.h"
+
+#include <fstream>
+#include <unordered_map>
+
+#include <sys/quota.h>
+
+#include <android-base/logging.h>
+
+#include "utils.h"
+
+namespace android {
+namespace installd {
+
+namespace {
+
+std::recursive_mutex mMountsLock;
+
+/* Map of all quota mounts from target to source */
+std::unordered_map<std::string, std::string> mQuotaReverseMounts;
+
+std::string& FindQuotaDeviceForUuid(const std::string& uuid) {
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+    auto path = create_data_path(uuid.empty() ? nullptr : uuid.c_str());
+    return mQuotaReverseMounts[path];
+}
+
+} // namespace
+
+bool InvalidateQuotaMounts() {
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+
+    mQuotaReverseMounts.clear();
+
+    std::ifstream in("/proc/mounts");
+    if (!in.is_open()) {
+        return false;
+    }
+
+    std::string source;
+    std::string target;
+    std::string ignored;
+    while (!in.eof()) {
+        std::getline(in, source, ' ');
+        std::getline(in, target, ' ');
+        std::getline(in, ignored);
+
+        if (source.compare(0, 11, "/dev/block/") == 0) {
+            struct dqblk dq;
+            if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
+                    reinterpret_cast<char*>(&dq)) == 0) {
+                LOG(DEBUG) << "Found quota mount " << source << " at " << target;
+                mQuotaReverseMounts[target] = source;
+            }
+        }
+    }
+    return true;
+}
+
+bool IsQuotaSupported(const std::string& uuid) {
+    return !FindQuotaDeviceForUuid(uuid).empty();
+}
+
+int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid) {
+    const std::string device = FindQuotaDeviceForUuid(uuid);
+    if (device == "") {
+        return -1;
+    }
+    struct dqblk dq;
+    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+            reinterpret_cast<char*>(&dq)) != 0) {
+        if (errno != ESRCH) {
+            PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+        }
+        return -1;
+    } else {
+#if MEASURE_DEBUG
+        LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
+#endif
+        return dq.dqb_curspace;
+    }
+}
+
+int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) {
+    const std::string device = FindQuotaDeviceForUuid(uuid);
+    if (device == "") {
+        return -1;
+    }
+    struct dqblk dq;
+    if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), gid,
+            reinterpret_cast<char*>(&dq)) != 0) {
+        if (errno != ESRCH) {
+            PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << gid;
+        }
+        return -1;
+    } else {
+#if MEASURE_DEBUG
+        LOG(DEBUG) << "quotactl() for GID " << gid << " " << dq.dqb_curspace;
+#endif
+        return dq.dqb_curspace;
+    }
+
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/QuotaUtils.h b/cmds/installd/QuotaUtils.h
new file mode 100644
index 0000000..9ad170f
--- /dev/null
+++ b/cmds/installd/QuotaUtils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_QUOTA_UTILS_H_
+#define ANDROID_INSTALLD_QUOTA_UTILS_H_
+
+#include <memory>
+#include <string>
+
+namespace android {
+namespace installd {
+
+/* Clear and recompute the reverse mounts map */
+bool InvalidateQuotaMounts();
+
+/* Whether quota is supported in the device with the given uuid */
+bool IsQuotaSupported(const std::string& uuid);
+
+/* Get the current occupied space in bytes for a uid or -1 if fails */
+int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid);
+
+/* Get the current occupied space in bytes for a gid or -1 if fails */
+int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid);
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // ANDROID_INSTALLD_QUOTA_UTILS_H_
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 03a411d..25e5247 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,42 +183,17 @@
     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) != NULL) {
-    count++;
-    pBuf = NULL;
-  }
-
-  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)) != NULL) {
-    argv[count++] = tok;
-    pBuf = NULL;
-  }
-
-  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) {
     static constexpr char kLocationSeparator = '/';
     const char *location = strrchr(path, kLocationSeparator);
-    if (location == NULL) {
+    if (location == nullptr) {
         return path;
     } else {
         // Skip the separator character.
@@ -224,341 +201,285 @@
     }
 }
 
-[[ noreturn ]]
-static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
-        const char* input_file_name, const char* output_file_name, int swap_fd,
-        const char* instruction_set, const char* compiler_filter,
-        bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
-        const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks,
-        bool generate_compact_dex, int dex_metadata_fd, const char* compilation_reason) {
-    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+// ExecVHelper prepares and holds pointers to parsed command line arguments so that no allocations
+// need to be performed between the fork and exec.
+class ExecVHelper {
+  public:
+    // Store a placeholder for the binary name.
+    ExecVHelper() : args_(1u, std::string()) {}
 
-    if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
-        LOG(ERROR) << "Instruction set '" << instruction_set << "' longer than max length of "
-                   << MAX_INSTRUCTION_SET_LEN;
-        exit(DexoptReturnCodes::kInstructionSetLength);
+    void PrepareArgs(const std::string& bin) {
+        CHECK(!args_.empty());
+        CHECK(args_[0].empty());
+        args_[0] = bin;
+        // Write char* into array.
+        for (const std::string& arg : args_) {
+            argv_.push_back(arg.c_str());
+        }
+        argv_.push_back(nullptr);  // Add null terminator.
     }
 
-    // Get the relative path to the input file.
-    const char* relative_input_file_name = get_location_from_path(input_file_name);
-
-    char dex2oat_Xms_flag[kPropertyValueMax];
-    bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0;
-
-    char dex2oat_Xmx_flag[kPropertyValueMax];
-    bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, NULL) > 0;
-
-    char dex2oat_threads_buf[kPropertyValueMax];
-    bool have_dex2oat_threads_flag = get_property(post_bootcomplete
-                                                      ? "dalvik.vm.dex2oat-threads"
-                                                      : "dalvik.vm.boot-dex2oat-threads",
-                                                  dex2oat_threads_buf,
-                                                  NULL) > 0;
-    char dex2oat_threads_arg[kPropertyValueMax + 2];
-    if (have_dex2oat_threads_flag) {
-        sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);
+    [[ noreturn ]]
+    void Exec(int exit_code) {
+        execv(argv_[0], (char * const *)&argv_[0]);
+        PLOG(ERROR) << "execv(" << argv_[0] << ") failed";
+        exit(exit_code);
     }
 
-    char dex2oat_isa_features_key[kPropertyKeyMax];
-    sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
-    char dex2oat_isa_features[kPropertyValueMax];
-    bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key,
-                                                  dex2oat_isa_features, NULL) > 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, NULL) > 0;
-
-    const char *dex2oat_norelocation = "-Xnorelocate";
-    bool have_dex2oat_relocation_skip_flag = false;
-
-    char dex2oat_flags[kPropertyValueMax];
-    int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags",
-                                 dex2oat_flags, NULL) <= 0 ? 0 : split_count(dex2oat_flags);
-    ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
-
-    // If we are booting without the real /data, don't spend time compiling.
-    char vold_decrypt[kPropertyValueMax];
-    bool have_vold_decrypt = get_property("vold.decrypt", vold_decrypt, "") > 0;
-    bool skip_compilation = (have_vold_decrypt &&
-                             (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||
-                             (strcmp(vold_decrypt, "1") == 0)));
-
-    bool generate_debug_info = property_get_bool("debug.generate-debug-info", false);
-
-    char app_image_format[kPropertyValueMax];
-    char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
-    bool have_app_image_format =
-            image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
-    if (have_app_image_format) {
-        sprintf(image_format_arg, "--image-format=%s", app_image_format);
-    }
-
-    char dex2oat_large_app_threshold[kPropertyValueMax];
-    bool have_dex2oat_large_app_threshold =
-            get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, NULL) > 0;
-    char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax];
-    if (have_dex2oat_large_app_threshold) {
-        sprintf(dex2oat_large_app_threshold_arg,
-                "--very-large-app-threshold=%s",
-                dex2oat_large_app_threshold);
-    }
-
-    // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
-    const char* dex2oat_bin = "/system/bin/dex2oat";
-    constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
-    // Do not use dex2oatd for release candidates (give dex2oat more soak time).
-    bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
-    if (is_debug_runtime() || (background_job_compile && is_debuggable_build() && !is_release)) {
-        if (access(kDex2oatDebugPath, X_OK) == 0) {
-            dex2oat_bin = kDex2oatDebugPath;
+    // Add an arg if it's not empty.
+    void AddArg(const std::string& arg) {
+        if (!arg.empty()) {
+            args_.push_back(arg);
         }
     }
 
-    bool generate_minidebug_info = kEnableMinidebugInfo &&
-            android::base::GetBoolProperty(kMinidebugInfoSystemProperty,
-                                           kMinidebugInfoSystemPropertyDefault);
-
-    static const char* RUNTIME_ARG = "--runtime-arg";
-
-    static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig
-
-    // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
-    // use arraysize instead.
-    char zip_fd_arg[arraysize("--zip-fd=") + MAX_INT_LEN];
-    char zip_location_arg[arraysize("--zip-location=") + PKG_PATH_MAX];
-    char input_vdex_fd_arg[arraysize("--input-vdex-fd=") + MAX_INT_LEN];
-    char output_vdex_fd_arg[arraysize("--output-vdex-fd=") + MAX_INT_LEN];
-    char oat_fd_arg[arraysize("--oat-fd=") + MAX_INT_LEN];
-    char oat_location_arg[arraysize("--oat-location=") + PKG_PATH_MAX];
-    char instruction_set_arg[arraysize("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
-    char instruction_set_variant_arg[arraysize("--instruction-set-variant=") + kPropertyValueMax];
-    char instruction_set_features_arg[arraysize("--instruction-set-features=") + kPropertyValueMax];
-    char dex2oat_Xms_arg[arraysize("-Xms") + kPropertyValueMax];
-    char dex2oat_Xmx_arg[arraysize("-Xmx") + kPropertyValueMax];
-    char dex2oat_compiler_filter_arg[arraysize("--compiler-filter=") + kPropertyValueMax];
-    bool have_dex2oat_swap_fd = false;
-    char dex2oat_swap_fd[arraysize("--swap-fd=") + MAX_INT_LEN];
-    bool have_dex2oat_image_fd = false;
-    char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];
-    size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX;
-    char target_sdk_version_arg[arraysize("-Xtarget-sdk-version:") + MAX_INT_LEN];
-    char class_loader_context_arg[class_loader_context_size];
-    if (class_loader_context != nullptr) {
-        snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s",
-            class_loader_context);
-    }
-
-    sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
-    sprintf(zip_location_arg, "--zip-location=%s", relative_input_file_name);
-    sprintf(input_vdex_fd_arg, "--input-vdex-fd=%d", input_vdex_fd);
-    sprintf(output_vdex_fd_arg, "--output-vdex-fd=%d", output_vdex_fd);
-    sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
-    sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
-    sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
-    sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant);
-    sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);
-    if (swap_fd >= 0) {
-        have_dex2oat_swap_fd = true;
-        sprintf(dex2oat_swap_fd, "--swap-fd=%d", swap_fd);
-    }
-    if (image_fd >= 0) {
-        have_dex2oat_image_fd = true;
-        sprintf(dex2oat_image_fd, "--app-image-fd=%d", image_fd);
-    }
-
-    if (have_dex2oat_Xms_flag) {
-        sprintf(dex2oat_Xms_arg, "-Xms%s", dex2oat_Xms_flag);
-    }
-    if (have_dex2oat_Xmx_flag) {
-        sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
-    }
-    sprintf(target_sdk_version_arg, "-Xtarget-sdk-version:%d", target_sdk_version);
-
-    // Compute compiler filter.
-
-    bool have_dex2oat_compiler_filter_flag = false;
-    if (skip_compilation) {
-        strlcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract",
-                sizeof(dex2oat_compiler_filter_arg));
-        have_dex2oat_compiler_filter_flag = true;
-        have_dex2oat_relocation_skip_flag = true;
-    } else if (compiler_filter != nullptr) {
-        if (strlen(compiler_filter) + strlen("--compiler-filter=") <
-                    arraysize(dex2oat_compiler_filter_arg)) {
-            sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
-            have_dex2oat_compiler_filter_flag = true;
-        } else {
-            ALOGW("Compiler filter name '%s' is too large (max characters is %zu)",
-                  compiler_filter,
-                  kPropertyValueMax);
+    // Add a runtime arg if it's not empty.
+    void AddRuntimeArg(const std::string& arg) {
+        if (!arg.empty()) {
+            args_.push_back("--runtime-arg");
+            args_.push_back(arg);
         }
     }
 
-    if (!have_dex2oat_compiler_filter_flag) {
-        char dex2oat_compiler_filter_flag[kPropertyValueMax];
-        have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",
-                                                         dex2oat_compiler_filter_flag, NULL) > 0;
-        if (have_dex2oat_compiler_filter_flag) {
-            sprintf(dex2oat_compiler_filter_arg,
-                    "--compiler-filter=%s",
-                    dex2oat_compiler_filter_flag);
-        }
-    }
+  protected:
+    // Holder arrays for backing arg storage.
+    std::vector<std::string> args_;
 
-    // Check whether all apps should be compiled debuggable.
-    if (!debuggable) {
-        char prop_buf[kPropertyValueMax];
-        debuggable =
-                (get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&
-                (prop_buf[0] == '1');
-    }
-    char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN];
-    if (profile_fd != -1) {
-        sprintf(profile_arg, "--profile-file-fd=%d", profile_fd);
-    }
+    // Argument poiners.
+    std::vector<const char*> argv_;
+};
 
-    // Get the directory of the apk to pass as a base classpath directory.
-    char base_dir[arraysize("--classpath-dir=") + PKG_PATH_MAX];
-    std::string apk_dir(input_file_name);
-    unsigned long dir_index = apk_dir.rfind('/');
-    bool has_base_dir = dir_index != std::string::npos;
-    if (has_base_dir) {
-        apk_dir = apk_dir.substr(0, dir_index);
-        sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());
-    }
-
-    std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
-
-    std::string compilation_reason_arg = compilation_reason == nullptr
-            ? ""
-            : std::string("--compilation-reason=") + compilation_reason;
-
-    ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
-
-    // Disable cdex if update input vdex is true since this combination of options is not
-    // supported.
-    const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
-
-    const char* argv[9  // program name, mandatory arguments and the final NULL
-                     + (have_dex2oat_isa_variant ? 1 : 0)
-                     + (have_dex2oat_isa_features ? 1 : 0)
-                     + (have_dex2oat_Xms_flag ? 2 : 0)
-                     + (have_dex2oat_Xmx_flag ? 2 : 0)
-                     + (have_dex2oat_compiler_filter_flag ? 1 : 0)
-                     + (have_dex2oat_threads_flag ? 1 : 0)
-                     + (have_dex2oat_swap_fd ? 1 : 0)
-                     + (have_dex2oat_image_fd ? 1 : 0)
-                     + (have_dex2oat_relocation_skip_flag ? 2 : 0)
-                     + (generate_debug_info ? 1 : 0)
-                     + (debuggable ? 1 : 0)
-                     + (have_app_image_format ? 1 : 0)
-                     + dex2oat_flags_count
-                     + (profile_fd == -1 ? 0 : 1)
-                     + (class_loader_context != nullptr ? 1 : 0)
-                     + (has_base_dir ? 1 : 0)
-                     + (have_dex2oat_large_app_threshold ? 1 : 0)
-                     + (disable_cdex ? 1 : 0)
-                     + (generate_minidebug_info ? 1 : 0)
-                     + (target_sdk_version != 0 ? 2 : 0)
-                     + (enable_hidden_api_checks ? 2 : 0)
-                     + (dex_metadata_fd > -1 ? 1 : 0)
-                     + (compilation_reason != nullptr ? 1 : 0)];
-    int i = 0;
-    argv[i++] = dex2oat_bin;
-    argv[i++] = zip_fd_arg;
-    argv[i++] = zip_location_arg;
-    argv[i++] = input_vdex_fd_arg;
-    argv[i++] = output_vdex_fd_arg;
-    argv[i++] = oat_fd_arg;
-    argv[i++] = oat_location_arg;
-    argv[i++] = instruction_set_arg;
-    if (have_dex2oat_isa_variant) {
-        argv[i++] = instruction_set_variant_arg;
-    }
-    if (have_dex2oat_isa_features) {
-        argv[i++] = instruction_set_features_arg;
-    }
-    if (have_dex2oat_Xms_flag) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = dex2oat_Xms_arg;
-    }
-    if (have_dex2oat_Xmx_flag) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = dex2oat_Xmx_arg;
-    }
-    if (have_dex2oat_compiler_filter_flag) {
-        argv[i++] = dex2oat_compiler_filter_arg;
-    }
-    if (have_dex2oat_threads_flag) {
-        argv[i++] = dex2oat_threads_arg;
-    }
-    if (have_dex2oat_swap_fd) {
-        argv[i++] = dex2oat_swap_fd;
-    }
-    if (have_dex2oat_image_fd) {
-        argv[i++] = dex2oat_image_fd;
-    }
-    if (generate_debug_info) {
-        argv[i++] = "--generate-debug-info";
-    }
-    if (debuggable) {
-        argv[i++] = "--debuggable";
-    }
-    if (have_app_image_format) {
-        argv[i++] = image_format_arg;
-    }
-    if (have_dex2oat_large_app_threshold) {
-        argv[i++] = dex2oat_large_app_threshold_arg;
-    }
-    if (dex2oat_flags_count) {
-        i += split(dex2oat_flags, argv + i);
-    }
-    if (have_dex2oat_relocation_skip_flag) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = dex2oat_norelocation;
-    }
-    if (profile_fd != -1) {
-        argv[i++] = profile_arg;
-    }
-    if (has_base_dir) {
-        argv[i++] = base_dir;
-    }
-    if (class_loader_context != nullptr) {
-        argv[i++] = class_loader_context_arg;
-    }
-    if (generate_minidebug_info) {
-        argv[i++] = kMinidebugDex2oatFlag;
-    }
-    if (disable_cdex) {
-        argv[i++] = kDisableCompactDexFlag;
-    }
-    if (target_sdk_version != 0) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = target_sdk_version_arg;
-    }
-    if (enable_hidden_api_checks) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = "-Xhidden-api-checks";
-    }
-
-    if (dex_metadata_fd > -1) {
-        argv[i++] = dex_metadata_fd_arg.c_str();
-    }
-
-    if(compilation_reason != nullptr) {
-        argv[i++] = compilation_reason_arg.c_str();
-    }
-    // Do not add after dex2oat_flags, they should override others for debugging.
-    argv[i] = NULL;
-
-    execv(dex2oat_bin, (char * const *)argv);
-    PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
-    exit(DexoptReturnCodes::kDex2oatExec);
+static std::string MapPropertyToArg(const std::string& property,
+                                    const std::string& format,
+                                    const std::string& default_value = "") {
+  std::string prop = GetProperty(property, default_value);
+  if (!prop.empty()) {
+    return StringPrintf(format.c_str(), prop.c_str());
+  }
+  return "";
 }
 
+class RunDex2Oat : public ExecVHelper {
+  public:
+    RunDex2Oat(int zip_fd,
+               int oat_fd,
+               int input_vdex_fd,
+               int output_vdex_fd,
+               int image_fd,
+               const char* input_file_name,
+               const char* output_file_name,
+               int swap_fd,
+               const char* instruction_set,
+               const char* compiler_filter,
+               bool debuggable,
+               bool post_bootcomplete,
+               bool background_job_compile,
+               int profile_fd,
+               const char* class_loader_context,
+               int target_sdk_version,
+               bool enable_hidden_api_checks,
+               bool generate_compact_dex,
+               int dex_metadata_fd,
+               const char* compilation_reason) {
+        // Get the relative path to the input file.
+        const char* relative_input_file_name = get_location_from_path(input_file_name);
+
+        std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
+        std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
+
+        const char* threads_property = post_bootcomplete
+                ? "dalvik.vm.dex2oat-threads"
+                : "dalvik.vm.boot-dex2oat-threads";
+        std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
+
+        const std::string dex2oat_isa_features_key =
+                StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
+        std::string instruction_set_features_arg =
+            MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
+
+        const std::string dex2oat_isa_variant_key =
+                StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
+        std::string instruction_set_variant_arg =
+            MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
+
+        const char* dex2oat_norelocation = "-Xnorelocate";
+
+        const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
+        std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
+        ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
+
+        // If we are booting without the real /data, don't spend time compiling.
+        std::string vold_decrypt = GetProperty("vold.decrypt", "");
+        bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
+                                vold_decrypt == "1";
+
+        const std::string resolve_startup_string_arg =
+                MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
+                                 "--resolve-startup-const-strings=%s");
+
+        const std::string image_block_size_arg =
+                MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size",
+                                 "--max-image-block-size=%s");
+
+        const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
+
+        std::string image_format_arg;
+        if (image_fd >= 0) {
+            image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
+        }
+
+        std::string dex2oat_large_app_threshold_arg =
+            MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
+
+        // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
+        const char* dex2oat_bin = "/system/bin/dex2oat";
+        constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+        // Do not use dex2oatd for release candidates (give dex2oat more soak time).
+        bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
+        if (is_debug_runtime() ||
+                (background_job_compile && is_debuggable_build() && !is_release)) {
+            if (access(kDex2oatDebugPath, X_OK) == 0) {
+                dex2oat_bin = kDex2oatDebugPath;
+            }
+        }
+
+        bool generate_minidebug_info = kEnableMinidebugInfo &&
+                GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
+
+        // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
+        // use arraysize instead.
+        std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
+        std::string zip_location_arg = StringPrintf("--zip-location=%s", relative_input_file_name);
+        std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
+        std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
+        std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
+        std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
+        std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
+        std::string dex2oat_compiler_filter_arg;
+        std::string dex2oat_swap_fd;
+        std::string dex2oat_image_fd;
+        std::string target_sdk_version_arg;
+        if (target_sdk_version != 0) {
+            StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
+        }
+        std::string class_loader_context_arg;
+        if (class_loader_context != nullptr) {
+            class_loader_context_arg = StringPrintf("--class-loader-context=%s",
+                                                    class_loader_context);
+        }
+
+        if (swap_fd >= 0) {
+            dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
+        }
+        if (image_fd >= 0) {
+            dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
+        }
+
+        // Compute compiler filter.
+        bool have_dex2oat_relocation_skip_flag = false;
+        if (skip_compilation) {
+            dex2oat_compiler_filter_arg = "--compiler-filter=extract";
+            have_dex2oat_relocation_skip_flag = true;
+        } else if (compiler_filter != nullptr) {
+            dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
+        }
+
+        if (dex2oat_compiler_filter_arg.empty()) {
+            dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
+                                                           "--compiler-filter=%s");
+        }
+
+        // Check whether all apps should be compiled debuggable.
+        if (!debuggable) {
+            debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
+        }
+        std::string profile_arg;
+        if (profile_fd != -1) {
+            profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
+        }
+
+        // Get the directory of the apk to pass as a base classpath directory.
+        std::string base_dir;
+        std::string apk_dir(input_file_name);
+        unsigned long dir_index = apk_dir.rfind('/');
+        bool has_base_dir = dir_index != std::string::npos;
+        if (has_base_dir) {
+            apk_dir = apk_dir.substr(0, dir_index);
+            base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
+        }
+
+        std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
+
+        std::string compilation_reason_arg = compilation_reason == nullptr
+                ? ""
+                : std::string("--compilation-reason=") + compilation_reason;
+
+        ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
+
+        // Disable cdex if update input vdex is true since this combination of options is not
+        // supported.
+        const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
+
+        AddArg(zip_fd_arg);
+        AddArg(zip_location_arg);
+        AddArg(input_vdex_fd_arg);
+        AddArg(output_vdex_fd_arg);
+        AddArg(oat_fd_arg);
+        AddArg(oat_location_arg);
+        AddArg(instruction_set_arg);
+
+        AddArg(instruction_set_variant_arg);
+        AddArg(instruction_set_features_arg);
+
+        AddRuntimeArg(dex2oat_Xms_arg);
+        AddRuntimeArg(dex2oat_Xmx_arg);
+
+        AddArg(resolve_startup_string_arg);
+        AddArg(image_block_size_arg);
+        AddArg(dex2oat_compiler_filter_arg);
+        AddArg(dex2oat_threads_arg);
+        AddArg(dex2oat_swap_fd);
+        AddArg(dex2oat_image_fd);
+
+        if (generate_debug_info) {
+            AddArg("--generate-debug-info");
+        }
+        if (debuggable) {
+            AddArg("--debuggable");
+        }
+        AddArg(image_format_arg);
+        AddArg(dex2oat_large_app_threshold_arg);
+
+        if (have_dex2oat_relocation_skip_flag) {
+            AddRuntimeArg(dex2oat_norelocation);
+        }
+        AddArg(profile_arg);
+        AddArg(base_dir);
+        AddArg(class_loader_context_arg);
+        if (generate_minidebug_info) {
+            AddArg(kMinidebugDex2oatFlag);
+        }
+        if (disable_cdex) {
+            AddArg(kDisableCompactDexFlag);
+        }
+        AddArg(target_sdk_version_arg);
+        if (enable_hidden_api_checks) {
+            AddRuntimeArg("-Xhidden-api-checks");
+        }
+
+        if (dex_metadata_fd > -1) {
+            AddArg(dex_metadata_fd_arg);
+        }
+
+        AddArg(compilation_reason_arg);
+
+        // Do not add args after dex2oat_flags, they should override others for debugging.
+        args_.insert(args_.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end());
+
+        PrepareArgs(dex2oat_bin);
+    }
+};
+
 /*
  * Whether dexopt should use a swap file when compiling an APK.
  *
@@ -580,13 +501,9 @@
     }
 
     // Check the "override" property. If it exists, return value == "true".
-    char dex2oat_prop_buf[kPropertyValueMax];
-    if (get_property("dalvik.vm.dex2oat-swap", dex2oat_prop_buf, "") > 0) {
-        if (strcmp(dex2oat_prop_buf, "true") == 0) {
-            return true;
-        } else {
-            return false;
-        }
+    std::string dex2oat_prop_buf = GetProperty("dalvik.vm.dex2oat-swap", "");
+    if (!dex2oat_prop_buf.empty()) {
+        return dex2oat_prop_buf == "true";
     }
 
     // Shortcut for default value. This is an implementation optimization for the process sketched
@@ -596,8 +513,7 @@
         return true;
     }
 
-    bool is_low_mem = property_get_bool("ro.config.low_ram", false);
-    if (is_low_mem) {
+    if (GetBoolProperty("ro.config.low_ram", false)) {
         return true;
     }
 
@@ -738,91 +654,91 @@
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
 
-[[ noreturn ]]
-static void run_profman(const std::vector<unique_fd>& profile_fds,
-                        const unique_fd& reference_profile_fd,
-                        const std::vector<unique_fd>* apk_fds,
-                        const std::vector<std::string>* dex_locations,
-                        bool copy_and_update) {
-    const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
+class RunProfman : public ExecVHelper {
+  public:
+   void SetupArgs(const std::vector<unique_fd>& profile_fds,
+                  const unique_fd& reference_profile_fd,
+                  const std::vector<unique_fd>& apk_fds,
+                  const std::vector<std::string>& dex_locations,
+                  bool copy_and_update) {
+        const char* profman_bin =
+                is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
 
-    if (copy_and_update) {
-        CHECK_EQ(1u, profile_fds.size());
-        CHECK(apk_fds != nullptr);
-        CHECK_EQ(1u, apk_fds->size());
-    }
-    std::vector<std::string> profile_args(profile_fds.size());
-    for (size_t k = 0; k < profile_fds.size(); k++) {
-        profile_args[k] = "--profile-file-fd=" + std::to_string(profile_fds[k].get());
-    }
-    std::string reference_profile_arg = "--reference-profile-file-fd="
-            + std::to_string(reference_profile_fd.get());
-
-    std::vector<std::string> apk_args;
-    if (apk_fds != nullptr) {
-        for (size_t k = 0; k < apk_fds->size(); k++) {
-            apk_args.push_back("--apk-fd=" + std::to_string((*apk_fds)[k].get()));
+        if (copy_and_update) {
+            CHECK_EQ(1u, profile_fds.size());
+            CHECK_EQ(1u, apk_fds.size());
         }
-    }
-
-    std::vector<std::string> dex_location_args;
-    if (dex_locations != nullptr) {
-        for (size_t k = 0; k < dex_locations->size(); k++) {
-            dex_location_args.push_back("--dex-location=" + (*dex_locations)[k]);
+        if (reference_profile_fd != -1) {
+            AddArg("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
         }
+
+        for (const unique_fd& fd : profile_fds) {
+            AddArg("--profile-file-fd=" + std::to_string(fd.get()));
+        }
+
+        for (const unique_fd& fd : apk_fds) {
+            AddArg("--apk-fd=" + std::to_string(fd.get()));
+        }
+
+        for (const std::string& dex_location : dex_locations) {
+            AddArg("--dex-location=" + dex_location);
+        }
+
+        if (copy_and_update) {
+            AddArg("--copy-and-update-profile-key");
+        }
+
+        // Do not add after dex2oat_flags, they should override others for debugging.
+        PrepareArgs(profman_bin);
     }
 
-    // program name, reference profile fd, the final NULL and the profile fds
-    const char* argv[3 + profile_args.size() + apk_args.size()
-            + dex_location_args.size() + (copy_and_update ? 1 : 0)];
-    int i = 0;
-    argv[i++] = profman_bin;
-    argv[i++] = reference_profile_arg.c_str();
-    for (size_t k = 0; k < profile_args.size(); k++) {
-        argv[i++] = profile_args[k].c_str();
-    }
-    for (size_t k = 0; k < apk_args.size(); k++) {
-        argv[i++] = apk_args[k].c_str();
-    }
-    for (size_t k = 0; k < dex_location_args.size(); k++) {
-        argv[i++] = dex_location_args[k].c_str();
-    }
-    if (copy_and_update) {
-        argv[i++] = "--copy-and-update-profile-key";
+    void SetupMerge(const std::vector<unique_fd>& profiles_fd,
+                    const unique_fd& reference_profile_fd,
+                    const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>(),
+                    const std::vector<std::string>& dex_locations = std::vector<std::string>()) {
+        SetupArgs(profiles_fd,
+                    reference_profile_fd,
+                    apk_fds,
+                    dex_locations,
+                    /*copy_and_update=*/false);
     }
 
-    // Do not add after dex2oat_flags, they should override others for debugging.
-    argv[i] = NULL;
+    void SetupCopyAndUpdate(unique_fd&& profile_fd,
+                            unique_fd&& reference_profile_fd,
+                            unique_fd&& apk_fd,
+                            const std::string& dex_location) {
+        // The fds need to stay open longer than the scope of the function, so put them into a local
+        // variable vector.
+        profiles_fd_.push_back(std::move(profile_fd));
+        apk_fds_.push_back(std::move(apk_fd));
+        reference_profile_fd_ = std::move(reference_profile_fd);
+        std::vector<std::string> dex_locations = {dex_location};
+        SetupArgs(profiles_fd_, reference_profile_fd_, apk_fds_, dex_locations,
+                  /*copy_and_update=*/true);
+    }
 
-    execv(profman_bin, (char * const *)argv);
-    PLOG(ERROR) << "execv(" << profman_bin << ") failed";
-    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
-}
+    void SetupDump(const std::vector<unique_fd>& profiles_fd,
+                   const unique_fd& reference_profile_fd,
+                   const std::vector<std::string>& dex_locations,
+                   const std::vector<unique_fd>& apk_fds,
+                   const unique_fd& output_fd) {
+        AddArg("--dump-only");
+        AddArg(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
+        SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
+                  /*copy_and_update=*/false);
+    }
 
-[[ noreturn ]]
-static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
-                              const unique_fd& reference_profile_fd,
-                              const std::vector<unique_fd>* apk_fds = nullptr,
-                              const std::vector<std::string>* dex_locations = nullptr) {
-    run_profman(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
-            /*copy_and_update*/false);
-}
+    void Exec() {
+        ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
+    }
 
-[[ noreturn ]]
-static void run_profman_copy_and_update(unique_fd&& profile_fd,
-                                        unique_fd&& reference_profile_fd,
-                                        unique_fd&& apk_fd,
-                                        const std::string& dex_location) {
-    std::vector<unique_fd> profiles_fd;
-    profiles_fd.push_back(std::move(profile_fd));
-    std::vector<unique_fd> apk_fds;
-    apk_fds.push_back(std::move(apk_fd));
-    std::vector<std::string> dex_locations;
-    dex_locations.push_back(dex_location);
+  private:
+    unique_fd reference_profile_fd_;
+    std::vector<unique_fd> profiles_fd_;
+    std::vector<unique_fd> apk_fds_;
+};
 
-    run_profman(profiles_fd, reference_profile_fd, &apk_fds, &dex_locations,
-            /*copy_and_update*/true);
-}
+
 
 // Decides if profile guided compilation is needed or not based on existing profiles.
 // The location is the package name for primary apks or the dex path for secondary dex files.
@@ -842,11 +758,13 @@
         return false;
     }
 
+    RunProfman profman_merge;
+    profman_merge.SetupMerge(profiles_fd, reference_profile_fd);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
-        run_profman_merge(profiles_fd, reference_profile_fd);
+        profman_merge.Exec();
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -919,42 +837,6 @@
     return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false);
 }
 
-[[ noreturn ]]
-static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
-                             const unique_fd& reference_profile_fd,
-                             const std::vector<std::string>& dex_locations,
-                             const std::vector<unique_fd>& apk_fds,
-                             const unique_fd& output_fd) {
-    std::vector<std::string> profman_args;
-    static const char* PROFMAN_BIN = "/system/bin/profman";
-    profman_args.push_back(PROFMAN_BIN);
-    profman_args.push_back("--dump-only");
-    profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
-    if (reference_profile_fd != -1) {
-        profman_args.push_back(StringPrintf("--reference-profile-file-fd=%d",
-                                            reference_profile_fd.get()));
-    }
-    for (size_t i = 0; i < profile_fds.size(); i++) {
-        profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fds[i].get()));
-    }
-    for (const std::string& dex_location : dex_locations) {
-        profman_args.push_back(StringPrintf("--dex-location=%s", dex_location.c_str()));
-    }
-    for (size_t i = 0; i < apk_fds.size(); i++) {
-        profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fds[i].get()));
-    }
-    const char **argv = new const char*[profman_args.size() + 1];
-    size_t i = 0;
-    for (const std::string& profman_arg : profman_args) {
-        argv[i++] = profman_arg.c_str();
-    }
-    argv[i] = NULL;
-
-    execv(PROFMAN_BIN, (char * const *)argv);
-    PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
-    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
-}
-
 bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
         const std::string& code_path) {
     std::vector<unique_fd> profile_fds;
@@ -991,12 +873,13 @@
     apk_fds.push_back(std::move(apk_fd));
 
 
+    RunProfman profman_dump;
+    profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds, output_fd);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
-        run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
-                         apk_fds, output_fd);
+        profman_dump.Exec();
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -1306,10 +1189,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, NULL) > 0;
-    if (!have_app_image_format) {
+    std::string app_image_format = GetProperty("dalvik.vm.appimageformat", "");
+    if (app_image_format.empty()) {
         return Dex2oatFileWrapper();
     }
     // Recreate is true since we do not want to modify a mapped image. If the app is
@@ -1570,70 +1451,60 @@
 // The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
 // If this is for a profile guided compilation, profile_was_updated will tell whether or not
 // the profile has changed.
-static void exec_dexoptanalyzer(const std::string& dex_file, int vdex_fd, int oat_fd,
-        int zip_fd, const std::string& instruction_set, const std::string& compiler_filter,
-        bool profile_was_updated, bool downgrade,
-        const char* class_loader_context) {
-    CHECK_GE(zip_fd, 0);
-    const char* dexoptanalyzer_bin =
-            is_debug_runtime()
-                    ? "/system/bin/dexoptanalyzerd"
-                    : "/system/bin/dexoptanalyzer";
-    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+class RunDexoptAnalyzer : public ExecVHelper {
+ public:
+    RunDexoptAnalyzer(const std::string& dex_file,
+                    int vdex_fd,
+                    int oat_fd,
+                    int zip_fd,
+                    const std::string& instruction_set,
+                    const std::string& compiler_filter,
+                    bool profile_was_updated,
+                    bool downgrade,
+                    const char* class_loader_context) {
+        CHECK_GE(zip_fd, 0);
+        const char* dexoptanalyzer_bin =
+                is_debug_runtime()
+                        ? "/system/bin/dexoptanalyzerd"
+                        : "/system/bin/dexoptanalyzer";
 
-    if (instruction_set.size() >= MAX_INSTRUCTION_SET_LEN) {
-        LOG(ERROR) << "Instruction set " << instruction_set
-                << " longer than max length of " << MAX_INSTRUCTION_SET_LEN;
-        return;
-    }
+        std::string dex_file_arg = "--dex-file=" + dex_file;
+        std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
+        std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
+        std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
+        std::string isa_arg = "--isa=" + instruction_set;
+        std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
+        const char* assume_profile_changed = "--assume-profile-changed";
+        const char* downgrade_flag = "--downgrade";
+        std::string class_loader_context_arg = "--class-loader-context=";
+        if (class_loader_context != nullptr) {
+            class_loader_context_arg += class_loader_context;
+        }
 
-    std::string dex_file_arg = "--dex-file=" + dex_file;
-    std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
-    std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
-    std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
-    std::string isa_arg = "--isa=" + instruction_set;
-    std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
-    const char* assume_profile_changed = "--assume-profile-changed";
-    const char* downgrade_flag = "--downgrade";
-    std::string class_loader_context_arg = "--class-loader-context=";
-    if (class_loader_context != nullptr) {
-        class_loader_context_arg += class_loader_context;
-    }
+        // program name, dex file, isa, filter
+        AddArg(dex_file_arg);
+        AddArg(isa_arg);
+        AddArg(compiler_filter_arg);
+        if (oat_fd >= 0) {
+            AddArg(oat_fd_arg);
+        }
+        if (vdex_fd >= 0) {
+            AddArg(vdex_fd_arg);
+        }
+        AddArg(zip_fd_arg.c_str());
+        if (profile_was_updated) {
+            AddArg(assume_profile_changed);
+        }
+        if (downgrade) {
+            AddArg(downgrade_flag);
+        }
+        if (class_loader_context != nullptr) {
+            AddArg(class_loader_context_arg.c_str());
+        }
 
-    // program name, dex file, isa, filter, the final NULL
-    const int argc = 6 +
-        (profile_was_updated ? 1 : 0) +
-        (vdex_fd >= 0 ? 1 : 0) +
-        (oat_fd >= 0 ? 1 : 0) +
-        (downgrade ? 1 : 0) +
-        (class_loader_context != nullptr ? 1 : 0);
-    const char* argv[argc];
-    int i = 0;
-    argv[i++] = dexoptanalyzer_bin;
-    argv[i++] = dex_file_arg.c_str();
-    argv[i++] = isa_arg.c_str();
-    argv[i++] = compiler_filter_arg.c_str();
-    if (oat_fd >= 0) {
-        argv[i++] = oat_fd_arg.c_str();
+        PrepareArgs(dexoptanalyzer_bin);
     }
-    if (vdex_fd >= 0) {
-        argv[i++] = vdex_fd_arg.c_str();
-    }
-    argv[i++] = zip_fd_arg.c_str();
-    if (profile_was_updated) {
-        argv[i++] = assume_profile_changed;
-    }
-    if (downgrade) {
-        argv[i++] = downgrade_flag;
-    }
-    if (class_loader_context != nullptr) {
-        argv[i++] = class_loader_context_arg.c_str();
-    }
-    argv[i] = NULL;
-
-    execv(dexoptanalyzer_bin, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
-}
+};
 
 // Prepares the oat dir for the secondary dex files.
 static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
@@ -1885,16 +1756,17 @@
                 /*is_secondary_dex*/true);
 
         // Run dexoptanalyzer to get dexopt_needed code. This is not expected to return.
-        exec_dexoptanalyzer(dex_path,
-                            vdex_file_fd.get(),
-                            oat_file_fd.get(),
-                            zip_fd.get(),
-                            instruction_set,
-                            compiler_filter, profile_was_updated,
-                            downgrade,
-                            class_loader_context);
-        PLOG(ERROR) << "Failed to exec dexoptanalyzer";
-        _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec);
+        // Note that we do not do it before the fork since opening the files is required to happen
+        // after forking.
+        RunDexoptAnalyzer run_dexopt_analyzer(dex_path,
+                                              vdex_file_fd.get(),
+                                              oat_file_fd.get(),
+                                              zip_fd.get(),
+                                              instruction_set,
+                                              compiler_filter, profile_was_updated,
+                                              downgrade,
+                                              class_loader_context);
+        run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
     }
 
     /* parent */
@@ -2063,6 +1935,27 @@
 
     LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
 
+    RunDex2Oat runner(input_fd.get(),
+                      out_oat_fd.get(),
+                      in_vdex_fd.get(),
+                      out_vdex_fd.get(),
+                      image_fd.get(),
+                      dex_path,
+                      out_oat_path,
+                      swap_fd.get(),
+                      instruction_set,
+                      compiler_filter,
+                      debuggable,
+                      boot_complete,
+                      background_job_compile,
+                      reference_profile_fd.get(),
+                      class_loader_context,
+                      target_sdk_version,
+                      enable_hidden_api_checks,
+                      generate_compact_dex,
+                      dex_metadata_fd.get(),
+                      compilation_reason);
+
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
@@ -2074,26 +1967,7 @@
             _exit(DexoptReturnCodes::kFlock);
         }
 
-        run_dex2oat(input_fd.get(),
-                    out_oat_fd.get(),
-                    in_vdex_fd.get(),
-                    out_vdex_fd.get(),
-                    image_fd.get(),
-                    dex_path,
-                    out_oat_path,
-                    swap_fd.get(),
-                    instruction_set,
-                    compiler_filter,
-                    debuggable,
-                    boot_complete,
-                    background_job_compile,
-                    reference_profile_fd.get(),
-                    class_loader_context,
-                    target_sdk_version,
-                    enable_hidden_api_checks,
-                    generate_compact_dex,
-                    dex_metadata_fd.get(),
-                    compilation_reason);
+        runner.Exec(DexoptReturnCodes::kDex2oatExec);
     } else {
         int res = wait_child(pid);
         if (res == 0) {
@@ -2421,18 +2295,14 @@
 
 bool move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) {
     // Get the current slot suffix. No suffix, no A/B.
-    std::string slot_suffix;
-    {
-        char buf[kPropertyValueMax];
-        if (get_property("ro.boot.slot_suffix", buf, nullptr) <= 0) {
-            return false;
-        }
-        slot_suffix = buf;
+    const std::string slot_suffix = GetProperty("ro.boot.slot_suffix", "");
+    if (slot_suffix.empty()) {
+        return false;
+    }
 
-        if (!ValidateTargetSlotSuffix(slot_suffix)) {
-            LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
-            return false;
-        }
+    if (!ValidateTargetSlotSuffix(slot_suffix)) {
+        LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
+        return false;
     }
 
     // Validate other inputs.
@@ -2661,11 +2531,13 @@
         return false;
     }
 
+    RunProfman args;
+    args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(app_shared_gid);
-        run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
+        args.Exec();
     }
 
     /* parent */
@@ -2689,6 +2561,13 @@
         return false;
     }
 
+    // Return false for empty class path since it may otherwise return true below if profiles is
+    // empty.
+    if (classpath.empty()) {
+        PLOG(ERROR) << "Class path is empty";
+        return false;
+    }
+
     // Open and create the snapshot profile.
     unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name);
 
@@ -2738,6 +2617,8 @@
                 profiles_fd.push_back(std::move(fd));
             }
         }
+        RunProfman args;
+        args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations);
         pid_t pid = fork();
         if (pid == 0) {
             /* child -- drop privileges before continuing */
@@ -2745,7 +2626,7 @@
 
             // The introduction of new access flags into boot jars causes them to
             // fail dex file verification.
-            run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
+            args.Exec();
         }
 
         /* parent */
@@ -2799,6 +2680,11 @@
         return false;
     }
 
+    RunProfman args;
+    args.SetupCopyAndUpdate(std::move(dex_metadata_fd),
+                            std::move(ref_profile_fd),
+                            std::move(apk_fd),
+                            code_path);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
@@ -2806,10 +2692,7 @@
         drop_capabilities(app_shared_gid);
 
         // The copy and update takes ownership over the fds.
-        run_profman_copy_and_update(std::move(dex_metadata_fd),
-                                    std::move(ref_profile_fd),
-                                    std::move(apk_fd),
-                                    code_path);
+        args.Exec();
     }
 
     /* parent */
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 95ed2ff..673ff0d 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -107,7 +107,7 @@
         DIR *dir;
         struct dirent *dirent;
         dir = opendir("/data/user");
-        if (dir != NULL) {
+        if (dir != nullptr) {
             while ((dirent = readdir(dir))) {
                 const char *name = dirent->d_name;
 
@@ -146,10 +146,10 @@
             closedir(dir);
 
             if (access(keychain_added_dir, F_OK) == 0) {
-                delete_dir_contents(keychain_added_dir, 1, 0);
+                delete_dir_contents(keychain_added_dir, 1, nullptr);
             }
             if (access(keychain_removed_dir, F_OK) == 0) {
-                delete_dir_contents(keychain_removed_dir, 1, 0);
+                delete_dir_contents(keychain_removed_dir, 1, nullptr);
             }
         }
 
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 28c7658..b2e7047 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -322,21 +322,8 @@
             return false;
         }
         const char* isa = parameters_.instruction_set;
-
-        // Check whether the file exists where expected.
         std::string dalvik_cache = GetOTADataDirectory() + "/" + DALVIK_CACHE;
         std::string isa_path = dalvik_cache + "/" + isa;
-        std::string art_path = isa_path + "/system@framework@boot.art";
-        std::string oat_path = isa_path + "/system@framework@boot.oat";
-        bool cleared = false;
-        if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) {
-            // Files exist, assume everything is alright if not forced. Otherwise clean up.
-            if (!force) {
-                return true;
-            }
-            ClearDirectory(isa_path);
-            cleared = true;
-        }
 
         // Reset umask in otapreopt, so that we control the the access for the files we create.
         umask(0);
@@ -355,17 +342,34 @@
             }
         }
 
-        // Prepare to create.
+        // Check whether we have files in /data.
+        // TODO: check that the files are correct wrt/ jars.
+        std::string art_path = isa_path + "/system@framework@boot.art";
+        std::string oat_path = isa_path + "/system@framework@boot.oat";
+        bool cleared = false;
+        if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) {
+            // Files exist, assume everything is alright if not forced. Otherwise clean up.
+            if (!force) {
+                return true;
+            }
+            ClearDirectory(isa_path);
+            cleared = true;
+        }
+
+        // Check whether we have an image in /system.
+        // TODO: check that the files are correct wrt/ jars.
+        std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
+        if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
+            // Note: we ignore |force| here.
+            return true;
+        }
+
+
         if (!cleared) {
             ClearDirectory(isa_path);
         }
 
-        std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
-        if (access(preopted_boot_art_path.c_str(), F_OK) != 0) {
-          // No preopted boot image. Try to compile.
-          return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
-        }
-        return true;
+        return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
     }
 
     static bool CreatePath(const std::string& path) {
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 8672206..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;
 
@@ -310,7 +311,7 @@
 
     std::string path(create_data_path(volume_uuid) + "/" + SECONDARY_USER_PREFIX);
     DIR* dir = opendir(path.c_str());
-    if (dir == NULL) {
+    if (dir == nullptr) {
         // Unable to discover other users, but at least return owner
         PLOG(ERROR) << "Failed to opendir " << path;
         return users;
@@ -340,13 +341,13 @@
     FTSENT *p;
     int64_t matchedSize = 0;
     char *argv[] = { (char*) path.c_str(), nullptr };
-    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
         if (errno != ENOENT) {
             PLOG(ERROR) << "Failed to fts_open " << path;
         }
         return -1;
     }
-    while ((p = fts_read(fts)) != NULL) {
+    while ((p = fts_read(fts)) != nullptr) {
         switch (p->fts_info) {
         case FTS_D:
         case FTS_DEFAULT:
@@ -469,7 +470,7 @@
                 continue;
             }
             subdir = fdopendir(subfd);
-            if (subdir == NULL) {
+            if (subdir == nullptr) {
                 ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
                 close(subfd);
                 result = -1;
@@ -495,11 +496,11 @@
 }
 
 int delete_dir_contents(const std::string& pathname, bool ignore_if_missing) {
-    return delete_dir_contents(pathname.c_str(), 0, NULL, ignore_if_missing);
+    return delete_dir_contents(pathname.c_str(), 0, nullptr, ignore_if_missing);
 }
 
 int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) {
-    return delete_dir_contents(pathname.c_str(), 1, NULL, ignore_if_missing);
+    return delete_dir_contents(pathname.c_str(), 1, nullptr, ignore_if_missing);
 }
 
 int delete_dir_contents(const char *pathname,
@@ -511,7 +512,7 @@
     DIR *d;
 
     d = opendir(pathname);
-    if (d == NULL) {
+    if (d == nullptr) {
         if (ignore_if_missing && (errno == ENOENT)) {
             return 0;
         }
@@ -540,12 +541,12 @@
         return -1;
     }
     d = fdopendir(fd);
-    if (d == NULL) {
+    if (d == nullptr) {
         ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
         close(fd);
         return -1;
     }
-    res = _delete_dir_contents(d, 0);
+    res = _delete_dir_contents(d, nullptr);
     closedir(d);
     return res;
 }
@@ -573,7 +574,7 @@
     }
 
     DIR *ds = fdopendir(sdfd);
-    if (ds == NULL) {
+    if (ds == nullptr) {
         ALOGE("Couldn't fdopendir: %s\n", strerror(errno));
         return -1;
     }
@@ -619,18 +620,18 @@
                    uid_t group)
 {
     int res = 0;
-    DIR *ds = NULL;
-    DIR *dd = NULL;
+    DIR *ds = nullptr;
+    DIR *dd = nullptr;
 
     ds = opendir(srcname);
-    if (ds == NULL) {
+    if (ds == nullptr) {
         ALOGE("Couldn't opendir %s: %s\n", srcname, strerror(errno));
         return -errno;
     }
 
     mkdir(dstname, 0600);
     dd = opendir(dstname);
-    if (dd == NULL) {
+    if (dd == nullptr) {
         ALOGE("Couldn't opendir %s: %s\n", dstname, strerror(errno));
         closedir(ds);
         return -errno;
@@ -964,11 +965,11 @@
     FTS *fts;
     FTSENT *p;
     char *argv[] = { (char*) path.c_str(), nullptr };
-    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
         PLOG(ERROR) << "Failed to fts_open " << path;
         return -1;
     }
-    while ((p = fts_read(fts)) != NULL) {
+    while ((p = fts_read(fts)) != nullptr) {
         switch (p->fts_info) {
         case FTS_DP:
             if (chmod(p->fts_path, target_mode) != 0) {
@@ -1036,8 +1037,8 @@
                 continue;
             }
 
-            DIR* subdir = fdopendir(subdir_fd);
-            if (subdir == NULL) {
+            DIR* subdir = Fdopendir(std::move(subdir_fd));
+            if (subdir == nullptr) {
                 PLOG(WARNING) << "Could not open dir path " << local_path;
                 result = false;
                 continue;
@@ -1055,7 +1056,7 @@
 
 bool collect_profiles(std::vector<std::string>* profiles_paths) {
     DIR* d = opendir(android_profiles_dir.c_str());
-    if (d == NULL) {
+    if (d == nullptr) {
         return false;
     } else {
         return collect_profiles(d, android_profiles_dir, profiles_paths);
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 5829c4f..d05724a 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -36,8 +36,6 @@
 #define BYPASS_QUOTA 0
 #define BYPASS_SDCARDFS 0
 
-#define APPLY_HARD_QUOTAS 0
-
 namespace android {
 namespace installd {
 
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index a6d7a78..c706d91 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -376,23 +376,23 @@
     }
 
     mServicesTable.setDescription(
-            "All binderized services (registered services through hwservicemanager)");
+            "| All binderized services (registered with hwservicemanager)");
     mPassthroughRefTable.setDescription(
-            "All interfaces that getService() has ever return as a passthrough interface;\n"
-            "PIDs / processes shown below might be inaccurate because the process\n"
-            "might have relinquished the interface or might have died.\n"
-            "The Server / Server CMD column can be ignored.\n"
-            "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
-            "the library and successfully fetched the passthrough implementation.");
+            "| All interfaces that getService() has ever returned as a passthrough interface;\n"
+            "| PIDs / processes shown below might be inaccurate because the process\n"
+            "| might have relinquished the interface or might have died.\n"
+            "| The Server / Server CMD column can be ignored.\n"
+            "| The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
+            "| the library and successfully fetched the passthrough implementation.");
     mImplementationsTable.setDescription(
-            "All available passthrough implementations (all -impl.so files).\n"
-            "These may return subclasses through their respective HIDL_FETCH_I* functions.");
+            "| All available passthrough implementations (all -impl.so files).\n"
+            "| These may return subclasses through their respective HIDL_FETCH_I* functions.");
     mManifestHalsTable.setDescription(
-            "All HALs that are in VINTF manifest.");
+            "| All HALs that are in VINTF manifest.");
     mLazyHalsTable.setDescription(
-            "All HALs that are declared in VINTF manifest:\n"
-            "   - as hwbinder HALs but are not registered to hwservicemanager, and\n"
-            "   - as hwbinder/passthrough HALs with no implementation.");
+            "| All HALs that are declared in VINTF manifest:\n"
+            "|    - as hwbinder HALs but are not registered to hwservicemanager, and\n"
+            "|    - as hwbinder/passthrough HALs with no implementation.");
 }
 
 bool ListCommand::addEntryWithInstance(const TableEntry& entry,
@@ -972,10 +972,10 @@
         thiz->mSelectedColumns.push_back(TableColumnType::VINTF);
         return OK;
     }, "print VINTF info. This column contains a comma-separated list of:\n"
-       "    - DM: device manifest\n"
-       "    - DC: device compatibility matrix\n"
-       "    - FM: framework manifest\n"
-       "    - FC: framework compatibility matrix"});
+       "    - DM: if the HAL is in the device manifest\n"
+       "    - DC: if the HAL is in the device compatibility matrix\n"
+       "    - FM: if the HAL is in the framework manifest\n"
+       "    - FC: if the HAL is in the framework compatibility matrix"});
     mOptions.push_back({'S', "service-status", no_argument, v++, [](ListCommand* thiz, const char*) {
         thiz->mSelectedColumns.push_back(TableColumnType::SERVICE_STATUS);
         return OK;
@@ -1054,7 +1054,7 @@
         return OK;
     }, "comma-separated list of one or more sections.\nThe output is restricted to the selected "
        "section(s). Valid options\nare: (b|binderized), (c|passthrough_clients), (l|"
-       "passthrough_libs), and (v|vintf).\nDefault is `bcl`."});
+       "passthrough_libs), (v|vintf), and (z|lazy).\nDefault is `bcl`."});
 }
 
 // Create 'longopts' argument to getopt_long. Caller is responsible for maintaining
@@ -1150,7 +1150,7 @@
     }
 
     if (mSelectedColumns.empty()) {
-        mSelectedColumns = {TableColumnType::RELEASED,
+        mSelectedColumns = {TableColumnType::VINTF, TableColumnType::RELEASED,
                             TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
                             TableColumnType::SERVER_PID, TableColumnType::CLIENT_PIDS};
     }
@@ -1210,7 +1210,7 @@
     err() << "list:" << std::endl
           << "    lshal" << std::endl
           << "    lshal list" << std::endl
-          << "        List all hals with default ordering and columns (`lshal list -liepc`)" << std::endl
+          << "        List all hals with default ordering and columns (`lshal list -Vliepc`)" << std::endl
           << "    lshal list [-h|--help]" << std::endl
           << "        -h, --help: Print help message for list (`lshal help list`)" << std::endl
           << "    lshal [list] [OPTIONS...]" << std::endl;
diff --git a/cmds/rss_hwm_reset/Android.bp b/cmds/rss_hwm_reset/Android.bp
new file mode 100644
index 0000000..15f10ef
--- /dev/null
+++ b/cmds/rss_hwm_reset/Android.bp
@@ -0,0 +1,28 @@
+// 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
+//
+//      https://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_binary {
+    name: "rss_hwm_reset",
+
+    srcs: [
+        "rss_hwm_reset.cc",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+
+    init_rc: ["rss_hwm_reset.rc"],
+}
diff --git a/cmds/rss_hwm_reset/rss_hwm_reset.cc b/cmds/rss_hwm_reset/rss_hwm_reset.cc
new file mode 100644
index 0000000..1626e7e
--- /dev/null
+++ b/cmds/rss_hwm_reset/rss_hwm_reset.cc
@@ -0,0 +1,72 @@
+/*
+ * 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
+ *
+ *      https://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.
+ */
+
+ /*
+  * rss_hwm_reset clears the RSS high-water mark counters for all currently
+  * running processes. It writes "5" to /proc/PID/clear_refs for every PID.
+  *
+  * It runs in its own process becuase dac_override capability is required
+  * in order to write to other processes' clear_refs.
+  *
+  * It is invoked from a system service by flipping sys.rss_hwm_reset.on
+  * property to "1".
+  */
+
+#define LOG_TAG "rss_hwm_reset"
+
+#include <dirent.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+
+namespace {
+// Resets RSS HWM counter for the selected process by writing 5 to
+// /proc/PID/clear_refs.
+void reset_rss_hwm(const char* pid) {
+    std::string clear_refs_path =
+            ::android::base::StringPrintf("/proc/%s/clear_refs", pid);
+    ::android::base::WriteStringToFile("5", clear_refs_path);
+}
+}
+
+// Clears RSS HWM counters for all currently running processes.
+int main(int /* argc */, char** /* argv[] */) {
+    DIR* dirp = opendir("/proc");
+    if (dirp == nullptr) {
+        ALOGE("unable to read /proc");
+        return 1;
+    }
+    struct dirent* entry;
+    while ((entry = readdir(dirp)) != nullptr) {
+        // Skip entries that are not directories.
+        if (entry->d_type != DT_DIR) continue;
+        // Skip entries that do not contain only numbers.
+        const char* pid = entry->d_name;
+        while (*pid) {
+            if (*pid < '0' || *pid > '9') break;
+            pid++;
+        }
+        if (*pid != 0) continue;
+
+        pid = entry->d_name;
+        reset_rss_hwm(pid);
+    }
+    closedir(dirp);
+    return 0;
+}
diff --git a/cmds/rss_hwm_reset/rss_hwm_reset.rc b/cmds/rss_hwm_reset/rss_hwm_reset.rc
new file mode 100644
index 0000000..fbbc820
--- /dev/null
+++ b/cmds/rss_hwm_reset/rss_hwm_reset.rc
@@ -0,0 +1,26 @@
+# 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
+#
+#      https://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.
+
+service rss_hwm_reset /system/bin/rss_hwm_reset
+    class late_start
+    disabled
+    oneshot
+    user nobody
+    group nobody readproc
+    writepid /dev/cpuset/system-background/tasks
+    capabilities DAC_OVERRIDE
+
+on property:sys.rss_hwm_reset.on=1
+    start rss_hwm_reset
+    setprop sys.rss_hwm_reset.on 0
diff --git a/headers/media_plugin/media/cas/DescramblerAPI.h b/headers/media_plugin/media/cas/DescramblerAPI.h
index 033c8ce..c57f606 100644
--- a/headers/media_plugin/media/cas/DescramblerAPI.h
+++ b/headers/media_plugin/media/cas/DescramblerAPI.h
@@ -72,12 +72,12 @@
     // associated MediaCas session is used to load decryption keys
     // into the crypto/cas plugin.  The keys are then referenced by key-id
     // in the 'key' parameter to the decrypt() method.
-    // Should return NO_ERROR on success, ERROR_DRM_SESSION_NOT_OPENED if
+    // Should return NO_ERROR on success, ERROR_CAS_SESSION_NOT_OPENED if
     // the session is not opened and a code from MediaErrors.h otherwise.
     virtual status_t setMediaCasSession(const CasSessionId& sessionId) = 0;
 
     // If the error returned falls into the range
-    // ERROR_DRM_VENDOR_MIN..ERROR_DRM_VENDOR_MAX, errorDetailMsg should be
+    // ERROR_CAS_VENDOR_MIN..ERROR_CAS_VENDOR_MAX, errorDetailMsg should be
     // filled in with an appropriate string.
     // At the java level these special errors will then trigger a
     // MediaCodec.CryptoException that gives clients access to both
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 4d24680..ed9531e 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -110,6 +110,47 @@
 
 #endif /* __ANDROID_API__ >= 23 */
 
+#if __ANDROID_API__ >= 29
+
+/**
+ * Look up the {|ns_class|, |ns_type|} Resource Record (RR) associated
+ * with Domain Name |dname| on the given |network|.
+ * The typical value for |ns_class| is ns_c_in, while |type| can be any
+ * record type (for instance, ns_t_aaaa or ns_t_txt).
+ *
+ * Returns a file descriptor to watch for read events, or a negative
+ * POSIX error code (see errno.h) if an immediate error occurs.
+ */
+int android_res_nquery(net_handle_t network,
+        const char *dname, int ns_class, int ns_type) __INTRODUCED_IN(29);
+
+/**
+ * Issue the query |msg| on the given |network|.
+ *
+ * Returns a file descriptor to watch for read events, or a negative
+ * POSIX error code (see errno.h) if an immediate error occurs.
+ */
+int android_res_nsend(net_handle_t network,
+        const unsigned char *msg, int msglen) __INTRODUCED_IN(29);
+
+/**
+ * Read a result for the query associated with the |fd| descriptor.
+ *
+ * Returns:
+ *     < 0: negative POSIX error code (see errno.h for possible values). |rcode| is not set.
+ *     >= 0: length of |answer|. |rcode| is the resolver return code (e.g., ns_r_nxdomain)
+ */
+int android_res_nresult(int fd,
+        int *rcode, unsigned char *answer, int anslen) __INTRODUCED_IN(29);
+
+/**
+ * Attempts to cancel the in-progress query associated with the |nsend_fd|
+ * descriptor.
+ */
+void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
+
 __END_DECLS
 
 #endif  // ANDROID_MULTINETWORK_H
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 1bd7c4f..f6cc3af 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -115,6 +115,7 @@
     return sEmptyDescriptor;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BBinder::transact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -137,6 +138,7 @@
     return err;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BBinder::linkToDeath(
     const sp<DeathRecipient>& /*recipient*/, void* /*cookie*/,
     uint32_t /*flags*/)
@@ -144,6 +146,7 @@
     return INVALID_OPERATION;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BBinder::unlinkToDeath(
     const wp<DeathRecipient>& /*recipient*/, void* /*cookie*/,
     uint32_t /*flags*/, wp<DeathRecipient>* /*outRecipient*/)
@@ -208,6 +211,7 @@
 }
 
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BBinder::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
 {
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 7342126..ec170f7 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -206,6 +206,7 @@
     return err;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BpBinder::transact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -220,6 +221,7 @@
     return DEAD_OBJECT;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BpBinder::linkToDeath(
     const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
 {
@@ -254,6 +256,7 @@
     return DEAD_OBJECT;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BpBinder::unlinkToDeath(
     const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
     wp<DeathRecipient>* outRecipient)
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp
index f9ec593..2f4dbee 100644
--- a/libs/binder/IAppOpsCallback.cpp
+++ b/libs/binder/IAppOpsCallback.cpp
@@ -49,6 +49,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnAppOpsCallback::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 068664b..fb0d521 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -129,6 +129,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnAppOpsService::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index ad1e69f..b307e3e 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -136,6 +136,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnBatteryStats::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 507ce53..307bc28 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) {
@@ -224,6 +226,7 @@
 BnMemory::~BnMemory() {
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnMemory::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -383,6 +386,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/Parcel.cpp b/libs/binder/Parcel.cpp
index b3ae09b..b2db945 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -467,7 +467,6 @@
 
 status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len)
 {
-    const sp<ProcessState> proc(ProcessState::self());
     status_t err;
     const uint8_t *data = parcel->mData;
     const binder_size_t *objects = parcel->mObjects;
@@ -520,6 +519,7 @@
     err = NO_ERROR;
 
     if (numObjects > 0) {
+        const sp<ProcessState> proc(ProcessState::self());
         // grow objects
         if (mObjectsCapacity < mObjectsSize + numObjects) {
             size_t newSize = ((mObjectsSize + numObjects)*3)/2;
@@ -2239,8 +2239,30 @@
     int32_t hasComm = readInt32();
     int fd = readFileDescriptor();
     if (hasComm != 0) {
-        // skip
-        readFileDescriptor();
+        // detach (owned by the binder driver)
+        int comm = readFileDescriptor();
+
+        // warning: this must be kept in sync with:
+        // frameworks/base/core/java/android/os/ParcelFileDescriptor.java
+        enum ParcelFileDescriptorStatus {
+            DETACHED = 2,
+        };
+
+#if BYTE_ORDER == BIG_ENDIAN
+        const int32_t message = ParcelFileDescriptorStatus::DETACHED;
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+        const int32_t message = __builtin_bswap32(ParcelFileDescriptorStatus::DETACHED);
+#endif
+
+        ssize_t written = TEMP_FAILURE_RETRY(
+            ::write(comm, &message, sizeof(message)));
+
+        if (written == -1 || written != sizeof(message)) {
+            ALOGW("Failed to detach ParcelFileDescriptor written: %zd err: %s",
+                written, strerror(errno));
+            return BAD_TYPE;
+        }
     }
     return fd;
 }
@@ -2521,8 +2543,11 @@
 
 void Parcel::releaseObjects()
 {
-    const sp<ProcessState> proc(ProcessState::self());
     size_t i = mObjectsSize;
+    if (i == 0) {
+        return;
+    }
+    sp<ProcessState> proc(ProcessState::self());
     uint8_t* const data = mData;
     binder_size_t* const objects = mObjects;
     while (i > 0) {
@@ -2535,8 +2560,11 @@
 
 void Parcel::acquireObjects()
 {
-    const sp<ProcessState> proc(ProcessState::self());
     size_t i = mObjectsSize;
+    if (i == 0) {
+        return;
+    }
+    const sp<ProcessState> proc(ProcessState::self());
     uint8_t* const data = mData;
     binder_size_t* const objects = mObjects;
     while (i > 0) {
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 3099bf5..db9f53a 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 a998529..e5d8ea6 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/.clang-format b/libs/binder/ndk/.clang-format
new file mode 100644
index 0000000..9a9d936
--- /dev/null
+++ b/libs/binder/ndk/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: Google
+ColumnLimit: 100
+IndentWidth: 4
+ContinuationIndentWidth: 8
+PointerAlignment: Left
+TabWidth: 4
+AllowShortFunctionsOnASingleLine: Inline
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 5461b4f..1b69dfd 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -23,6 +23,8 @@
         "include_apex",
     ],
 
+    cflags: ["-Wall", "-Wextra", "-Werror"],
+
     srcs: [
         "ibinder.cpp",
         "ibinder_jni.cpp",
@@ -38,6 +40,12 @@
         "libbinder",
         "libutils",
     ],
+
+    version_script: "libbinder_ndk.map.txt",
+    stubs: {
+        symbol_file: "libbinder_ndk.map.txt",
+        versions: ["29"],
+    },
 }
 
 ndk_headers {
@@ -48,10 +56,12 @@
         "include_ndk/android/*.h",
     ],
     license: "NOTICE",
+    draft: true,
 }
 
 ndk_library {
     name: "libbinder_ndk",
     symbol_file: "libbinder_ndk.map.txt",
     first_version: "29",
+    draft: true,
 }
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 896c5c1..f9c8c8a 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -22,6 +22,7 @@
 #include "status_internal.h"
 
 #include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
 
 using DeathRecipient = ::android::IBinder::DeathRecipient;
 
@@ -45,7 +46,7 @@
     return binder != nullptr && binder->findObject(kId) == kValue;
 }
 
-} // namespace ABBinderTag
+}  // namespace ABBinderTag
 
 namespace ABpBinderTag {
 
@@ -60,7 +61,7 @@
     delete static_cast<Value*>(obj);
 };
 
-} // namespace ABpBinderTag
+}  // namespace ABpBinderTag
 
 AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
 AIBinder::~AIBinder() {}
@@ -91,7 +92,7 @@
         return false;
     }
 
-    CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor
+    CHECK(asABpBinder() != nullptr);  // ABBinder always has a descriptor
 
     String8 descriptor(getBinder()->getInterfaceDescriptor());
     if (descriptor != newDescriptor) {
@@ -107,7 +108,7 @@
 }
 
 ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData)
-      : AIBinder(clazz), BBinder(), mUserData(userData) {
+    : AIBinder(clazz), BBinder(), mUserData(userData) {
     CHECK(clazz != nullptr);
 }
 ABBinder::~ABBinder() {
@@ -136,7 +137,7 @@
 }
 
 ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder)
-      : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
+    : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
     CHECK(binder != nullptr);
 }
 ABpBinder::~ABpBinder() {}
@@ -214,10 +215,10 @@
 AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
                                AIBinder_Class_onDestroy onDestroy,
                                AIBinder_Class_onTransact onTransact)
-      : onCreate(onCreate),
-        onDestroy(onDestroy),
-        onTransact(onTransact),
-        mInterfaceDescriptor(interfaceDescriptor) {}
+    : onCreate(onCreate),
+      onDestroy(onDestroy),
+      onTransact(onTransact),
+      mInterfaceDescriptor(interfaceDescriptor) {}
 
 AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
                                       AIBinder_Class_onCreate onCreate,
@@ -239,7 +240,7 @@
 }
 
 AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied)
-      : mOnDied(onDied) {
+    : mOnDied(onDied) {
     CHECK(onDied != nullptr);
 }
 
@@ -302,7 +303,7 @@
 
 bool AIBinder_isRemote(const AIBinder* binder) {
     if (binder == nullptr) {
-        return true;
+        return false;
     }
 
     return binder->isRemote();
@@ -346,6 +347,14 @@
     return recipient->unlinkToDeath(binder, cookie);
 }
 
+uid_t AIBinder_getCallingUid() {
+    return ::android::IPCThreadState::self()->getCallingUid();
+}
+
+pid_t AIBinder_getCallingPid() {
+    return ::android::IPCThreadState::self()->getCallingPid();
+}
+
 void AIBinder_incStrong(AIBinder* binder) {
     if (binder == nullptr) {
         LOG(ERROR) << __func__ << ": on null binder";
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 5b6bc94..ac592ea 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -49,7 +49,7 @@
         return binder->remoteBinder() != nullptr;
     }
 
-private:
+   private:
     // AIBinder instance is instance of this class for a local object. In order to transact on a
     // remote object, this also must be set for simplicity (although right now, only the
     // interfaceDescriptor from it is used).
@@ -69,7 +69,7 @@
     ::android::status_t onTransact(uint32_t code, const ::android::Parcel& data,
                                    ::android::Parcel* reply, binder_flags_t flags) override;
 
-private:
+   private:
     ABBinder(const AIBinder_Class* clazz, void* userData);
 
     // only thing that should create an ABBinder
@@ -96,7 +96,7 @@
     ::android::sp<::android::IBinder> getBinder() override { return remote(); }
     ABpBinder* asABpBinder() override { return this; }
 
-private:
+   private:
     ABpBinder(const ::android::sp<::android::IBinder>& binder);
 };
 
@@ -110,7 +110,7 @@
     const AIBinder_Class_onDestroy onDestroy;
     const AIBinder_Class_onTransact onTransact;
 
-private:
+   private:
     // This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
     // one.
     const ::android::String16 mInterfaceDescriptor;
@@ -128,14 +128,14 @@
     struct TransferDeathRecipient : ::android::IBinder::DeathRecipient {
         TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie,
                                const AIBinder_DeathRecipient_onBinderDied& onDied)
-              : mWho(who), mCookie(cookie), mOnDied(onDied) {}
+            : mWho(who), mCookie(cookie), mOnDied(onDied) {}
 
         void binderDied(const ::android::wp<::android::IBinder>& who) override;
 
         const ::android::wp<::android::IBinder>& getWho() { return mWho; }
         void* getCookie() { return mCookie; }
 
-    private:
+       private:
         ::android::wp<::android::IBinder> mWho;
         void* mCookie;
         const AIBinder_DeathRecipient_onBinderDied& mOnDied;
@@ -145,7 +145,7 @@
     binder_status_t linkToDeath(AIBinder* binder, void* cookie);
     binder_status_t unlinkToDeath(AIBinder* binder, void* cookie);
 
-private:
+   private:
     std::mutex mDeathRecipientsMutex;
     std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients;
     AIBinder_DeathRecipient_onBinderDied mOnDied;
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_apex/android/binder_manager.h
index b8f38ba..80b6c07 100644
--- a/libs/binder/ndk/include_apex/android/binder_manager.h
+++ b/libs/binder/ndk/include_apex/android/binder_manager.h
@@ -17,11 +17,18 @@
 #pragma once
 
 #include <android/binder_ibinder.h>
+#include <android/binder_status.h>
 
 __BEGIN_DECLS
 
 /**
- * This registers the service with the default service manager under this instance name.
+ * This registers the service with the default service manager under this instance name. This does
+ * not take ownership of binder.
+ *
+ * \param binder object to register globally with the service manager.
+ * \param instance identifier of the service. This will be used to lookup the service.
+ *
+ * \return STATUS_OK on success.
  */
 binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance);
 
@@ -29,6 +36,8 @@
  * Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
  * it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
  * for calling AIBinder_decStrong).
+ *
+ * \param instance identifier of the service used to lookup the service.
  */
 __attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
 
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index cc0a29d..ff1860e 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -32,8 +32,7 @@
 
 #include <assert.h>
 
-#ifdef __cplusplus
-
+#include <unistd.h>
 #include <cstddef>
 
 namespace ndk {
@@ -42,7 +41,7 @@
  * Represents one strong pointer to an AIBinder object.
  */
 class SpAIBinder {
-public:
+   public:
     /**
      * Takes ownership of one strong refcount of binder.
      */
@@ -106,30 +105,30 @@
      */
     AIBinder** getR() { return &mBinder; }
 
-private:
+   private:
     AIBinder* mBinder = nullptr;
 };
 
 /**
  * This baseclass owns a single object, used to make various classes RAII.
  */
-template <typename T, void (*Destroy)(T*)>
+template <typename T, typename R, R (*Destroy)(T), T DEFAULT>
 class ScopedAResource {
-public:
+   public:
     /**
      * Takes ownership of t.
      */
-    explicit ScopedAResource(T* t = nullptr) : mT(t) {}
+    explicit ScopedAResource(T t = DEFAULT) : mT(t) {}
 
     /**
      * This deletes the underlying object if it exists. See set.
      */
-    ~ScopedAResource() { set(nullptr); }
+    ~ScopedAResource() { set(DEFAULT); }
 
     /**
      * Takes ownership of t.
      */
-    void set(T* t) {
+    void set(T t) {
         Destroy(mT);
         mT = t;
     }
@@ -137,12 +136,12 @@
     /**
      * This returns the underlying object to be modified but does not affect ownership.
      */
-    T* get() { return mT; }
+    T get() { return mT; }
 
     /**
      * This returns the const underlying object but does not affect ownership.
      */
-    const T* get() const { return mT; }
+    const T get() const { return mT; }
 
     /**
      * This allows the value in this class to be set from beneath it. If you call this method and
@@ -156,7 +155,7 @@
      * Other usecases are discouraged.
      *
      */
-    T** getR() { return &mT; }
+    T* getR() { return &mT; }
 
     // copy-constructing, or move/copy assignment is disallowed
     ScopedAResource(const ScopedAResource&) = delete;
@@ -164,17 +163,17 @@
     ScopedAResource& operator=(ScopedAResource&&) = delete;
 
     // move-constructing is okay
-    ScopedAResource(ScopedAResource&&) = default;
+    ScopedAResource(ScopedAResource&& other) : mT(std::move(other.mT)) { other.mT = DEFAULT; }
 
-private:
-    T* mT;
+   private:
+    T mT;
 };
 
 /**
  * Convenience wrapper. See AParcel.
  */
-class ScopedAParcel : public ScopedAResource<AParcel, AParcel_delete> {
-public:
+class ScopedAParcel : public ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
+   public:
     /**
      * Takes ownership of a.
      */
@@ -186,8 +185,8 @@
 /**
  * Convenience wrapper. See AStatus.
  */
-class ScopedAStatus : public ScopedAResource<AStatus, AStatus_delete> {
-public:
+class ScopedAStatus : public ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
+   public:
     /**
      * Takes ownership of a.
      */
@@ -199,19 +198,25 @@
      * See AStatus_isOk.
      */
     bool isOk() { return get() != nullptr && AStatus_isOk(get()); }
+
+    /**
+     * Convenience method for okay status.
+     */
+    static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); }
 };
 
 /**
  * Convenience wrapper. See AIBinder_DeathRecipient.
  */
 class ScopedAIBinder_DeathRecipient
-      : public ScopedAResource<AIBinder_DeathRecipient, AIBinder_DeathRecipient_delete> {
-public:
+    : public ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
+                             nullptr> {
+   public:
     /**
      * Takes ownership of a.
      */
     explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr)
-          : ScopedAResource(a) {}
+        : ScopedAResource(a) {}
     ~ScopedAIBinder_DeathRecipient() {}
     ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default;
 };
@@ -219,8 +224,9 @@
 /**
  * Convenience wrapper. See AIBinder_Weak.
  */
-class ScopedAIBinder_Weak : public ScopedAResource<AIBinder_Weak, AIBinder_Weak_delete> {
-public:
+class ScopedAIBinder_Weak
+    : public ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
+   public:
     /**
      * Takes ownership of a.
      */
@@ -234,8 +240,19 @@
     SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
 };
 
-} // namespace ndk
+/**
+ * Convenience wrapper for a file descriptor.
+ */
+class ScopedFileDescriptor : public ScopedAResource<int, int, close, -1> {
+   public:
+    /**
+     * Takes ownership of a.
+     */
+    explicit ScopedFileDescriptor(int a = -1) : ScopedAResource(a) {}
+    ~ScopedFileDescriptor() {}
+    ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
+};
 
-#endif // __cplusplus
+}  // namespace ndk
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index c222c16..9c6c55e 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -28,6 +28,7 @@
 
 #include <stdint.h>
 #include <sys/cdefs.h>
+#include <sys/types.h>
 
 #include <android/binder_parcel.h>
 #include <android/binder_status.h>
@@ -126,8 +127,9 @@
 /**
  * This is called whenever a new AIBinder object is needed of a specific class.
  *
- * These arguments are passed from AIBinder_new. The return value is stored and can be retrieved
- * using AIBinder_getUserData.
+ * \param args these can be used to construct a new class. These are passed from AIBinder_new.
+ * \return this is the userdata representing the class. It can be retrieved using
+ * AIBinder_getUserData.
  */
 typedef void* (*AIBinder_Class_onCreate)(void* args);
 
@@ -135,23 +137,41 @@
  * This is called whenever an AIBinder object is no longer referenced and needs destroyed.
  *
  * Typically, this just deletes whatever the implementation is.
+ *
+ * \param userData this is the same object returned by AIBinder_Class_onCreate
  */
 typedef void (*AIBinder_Class_onDestroy)(void* userData);
 
 /**
  * This is called whenever a transaction needs to be processed by a local implementation.
+ *
+ * \param binder the object being transacted on.
+ * \param code implementation-specific code representing which transaction should be taken.
+ * \param in the implementation-specific input data to this transaction.
+ * \param out the implementation-specific output data to this transaction.
+ *
+ * \return the implementation-specific output code. This may be forwarded from another service, the
+ * result of a parcel read or write, or another error as is applicable to the specific
+ * implementation. Usually, implementation-specific error codes are written to the output parcel,
+ * and the transaction code is reserved for kernel errors or error codes that have been repeated
+ * from subsequent transactions.
  */
 typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, transaction_code_t code,
                                                      const AParcel* in, AParcel* out);
 
 /**
- * An interfaceDescriptor uniquely identifies the type of object that is being created. This is used
- * internally for sanity checks on transactions.
+ * This creates a new instance of a class of binders which can be instantiated. This is called one
+ * time during library initialization and cleaned up when the process exits or execs.
  *
- * None of these parameters can be nullptr.
+ * None of these parameters can be null.
  *
- * This is created one time during library initialization and cleaned up when the process exits or
- * execs.
+ * \param interfaceDescriptor this is a unique identifier for the class. This is used internally for
+ * sanity checks on transactions.
+ * \param onCreate see AIBinder_Class_onCreate.
+ * \param onDestroy see AIBinder_Class_onDestroy.
+ * \param onTransact see AIBinder_Class_onTransact.
+ *
+ * \return the class object representing these parameters or null on error.
  */
 __attribute__((warn_unused_result)) AIBinder_Class* AIBinder_Class_define(
         const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
@@ -174,12 +194,21 @@
  * hypothetical removeCallback function, the remote process would have no way to determine that
  * these two objects are actually equal using the AIBinder pointer alone (which they should be able
  * to do). Also see the suggested memory ownership model suggested above.
+ *
+ * \param clazz the type of the object to be created.
+ * \param args the args to pass to AIBinder_onCreate for that class.
+ *
+ * \return a binder object representing the newly instantiated object.
  */
 __attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args)
         __INTRODUCED_IN(29);
 
 /**
  * If this is hosted in a process other than the current one.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return true if the AIBinder represents an object in another process.
  */
 bool AIBinder_isRemote(const AIBinder* binder) __INTRODUCED_IN(29);
 
@@ -189,13 +218,21 @@
  * this is automatically updated to reflect the current alive status of this binder. This will be
  * updated as the result of a transaction made using AIBinder_transact, but it will also be updated
  * based on the results of bookkeeping or other transactions made internally.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return true if the binder is alive.
  */
 bool AIBinder_isAlive(const AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
- * Built-in transaction for all binder objects. This sends a transaction which will immediately
+ * Built-in transaction for all binder objects. This sends a transaction that will immediately
  * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a
  * sanity check.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return STATUS_OK if the ping succeeds.
  */
 binder_status_t AIBinder_ping(AIBinder* binder) __INTRODUCED_IN(29);
 
@@ -209,6 +246,12 @@
  * identification and holding user data.
  *
  * If binder is local, this will return STATUS_INVALID_OPERATION.
+ *
+ * \param binder the binder object you want to receive death notifications from.
+ * \param recipient the callback that will receive notifications when/if the binder dies.
+ * \param cookie the value that will be passed to the death recipient on death.
+ *
+ * \return STATUS_OK on success.
  */
 binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                      void* cookie) __INTRODUCED_IN(29);
@@ -217,22 +260,62 @@
  * Stops registration for the associated binder dying. Does not delete the recipient. This function
  * may return a binder transaction failure and in case the death recipient cannot be found, it
  * returns STATUS_NAME_NOT_FOUND.
+ *
+ * \param binder the binder object to remove a previously linked death recipient from.
+ * \param recipient the callback to remove.
+ * \param cookie the cookie used to link to death.
+ *
+ * \return STATUS_OK on success. STATUS_NAME_NOT_FOUND if the binder cannot be found to be unlinked.
  */
 binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                        void* cookie) __INTRODUCED_IN(29);
 
 /**
+ * This returns the calling UID assuming that this thread is called from a thread that is processing
+ * a binder transaction (for instance, in the implementation of AIBinder_Class_onTransact).
+ *
+ * This can be used with higher-level system services to determine the caller's identity and check
+ * permissions.
+ *
+ * \return calling uid or the current process's UID if this thread isn't processing a transaction.
+ */
+uid_t AIBinder_getCallingUid();
+
+/**
+ * This returns the calling PID assuming that this thread is called from a thread that is processing
+ * a binder transaction (for instance, in the implementation of AIBinder_Class_onTransact).
+ *
+ * This can be used with higher-level system services to determine the caller's identity and check
+ * permissions. However, when doing this, one should be aware of possible TOCTOU problems when the
+ * calling process dies and is replaced with another process with elevated permissions and the same
+ * PID.
+ *
+ * \return calling pid or the current process's PID if this thread isn't processing a transaction.
+ * If the transaction being processed is a oneway transaction, then this method will return 0.
+ */
+pid_t AIBinder_getCallingPid();
+
+/**
  * This can only be called if a strong reference to this object already exists in process.
+ *
+ * \param binder the binder object to add a refcount to.
  */
 void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * This will delete the object and call onDestroy once the refcount reaches zero.
+ *
+ * \param binder the binder object to remove a refcount from.
  */
 void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * For debugging only!
+ *
+ * \param binder the binder object to retrieve the refcount of.
+ *
+ * \return the number of strong-refs on this binder in this process. If binder is null, this will be
+ * -1.
  */
 int32_t AIBinder_debugGetRefCount(AIBinder* binder) __INTRODUCED_IN(29);
 
@@ -244,17 +327,32 @@
  *
  * This returns true if the class association succeeds. If it fails, no change is made to the
  * binder object.
+ *
+ * \param binder the object to attach the class to.
+ * \param clazz the clazz to attach to binder.
+ *
+ * \return true if the binder has the class clazz and if the association was successful.
  */
 bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) __INTRODUCED_IN(29);
 
 /**
  * Returns the class that this binder was constructed with or associated with.
+ *
+ * \param binder the object that is being queried.
+ *
+ * \return the class that this binder is associated with. If this binder wasn't created with
+ * AIBinder_new, and AIBinder_associateClass hasn't been called, then this will return null.
  */
 const AIBinder_Class* AIBinder_getClass(AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * Value returned by onCreate for a local binder. For stateless classes (if onCreate returns
- * nullptr), this also returns nullptr. For a remote binder, this will always return nullptr.
+ * null), this also returns null. For a remote binder, this will always return null.
+ *
+ * \param binder the object that is being queried.
+ *
+ * \return the userdata returned from AIBinder_onCreate when this object was created. This may be
+ * null for stateless objects. For remote objects, this is always null.
  */
 void* AIBinder_getUserData(AIBinder* binder) __INTRODUCED_IN(29);
 
@@ -278,6 +376,12 @@
  * ownership is passed to the caller. At this point, the parcel can be filled out and passed to
  * AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be
  * deleted with AParcel_delete.
+ *
+ * \param binder the binder object to start a transaction on.
+ * \param in out parameter for input data to the transaction.
+ *
+ * \return STATUS_OK on success. This will return STATUS_INVALID_OPERATION if the binder has not yet
+ * been associated with a class (see AIBinder_new and AIBinder_associateClass).
  */
 binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) __INTRODUCED_IN(29);
 
@@ -292,6 +396,16 @@
  *
  * This does not affect the ownership of binder. The out parcel's ownership is passed to the caller
  * and must be released with AParcel_delete when finished reading.
+ *
+ * \param binder the binder object to transact on.
+ * \param code the implementation-specific code representing which transaction should be taken.
+ * \param in the implementation-specific input data to this transaction.
+ * \param out the implementation-specific output data to this transaction.
+ * \param flags possible flags to alter the way in which the transaction is conducted or 0.
+ *
+ * \return the result from the kernel or from the remote process. Usually, implementation-specific
+ * error codes are written to the output parcel, and the transaction code is reserved for kernel
+ * errors or error codes that have been repeated from subsequent transactions.
  */
 binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
                                   AParcel** out, binder_flags_t flags) __INTRODUCED_IN(29);
@@ -299,29 +413,45 @@
 /**
  * This does not take any ownership of the input binder, but it can be used to retrieve it if
  * something else in some process still holds a reference to it.
+ *
+ * \param binder object to create a weak pointer to.
+ *
+ * \return object representing a weak pointer to binder (or null if binder is null).
  */
 __attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder)
         __INTRODUCED_IN(29);
 
 /**
  * Deletes the weak reference. This will have no impact on the lifetime of the binder.
+ *
+ * \param weakBinder object created with AIBinder_Weak_new.
  */
 void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29);
 
 /**
  * If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns
- * nullptr.
+ * null.
+ *
+ * \param weakBinder weak pointer to attempt retrieving the original object from.
+ *
+ * \return an AIBinder object with one refcount given to the caller or null.
  */
 __attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder)
         __INTRODUCED_IN(29);
 
 /**
  * This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
+ *
+ * \param cookie the cookie passed to AIBinder_linkToDeath.
  */
 typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29);
 
 /**
  * Creates a new binder death recipient. This can be attached to multiple different binder objects.
+ *
+ * \param onBinderDied the callback to call when this death recipient is invoked.
+ *
+ * \return the newly constructed object (or null if onBinderDied is null).
  */
 __attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
         AIBinder_DeathRecipient_onBinderDied onBinderDied) __INTRODUCED_IN(29);
@@ -329,10 +459,12 @@
 /**
  * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
  * calling this as these will all be automatically unlinked.
+ *
+ * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new).
  */
 void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29);
 
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
index 81fb3c5..124f36c 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -39,6 +39,12 @@
  * If either env or the binder is null, null is returned. If this binder object was originally an
  * AIBinder object, the original object is returned. The returned object has one refcount
  * associated with it, and so this should be accompanied with an AIBinder_decStrong call.
+ *
+ * \param env Java environment.
+ * \param binder android.os.IBinder java object.
+ *
+ * \return an AIBinder object representing the Java binder object. If either parameter is null, or
+ * the Java object is of the wrong type, this will return null.
  */
 __attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder)
         __INTRODUCED_IN(29);
@@ -48,11 +54,16 @@
  *
  * If either env or the binder is null, null is returned. If this binder object was originally an
  * IBinder object, the original java object will be returned.
+ *
+ * \param env Java environment.
+ * \param binder the object to convert.
+ *
+ * \return an android.os.IBinder object or null if the parameters were null.
  */
 __attribute__((warn_unused_result)) jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder)
         __INTRODUCED_IN(29);
 
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
index e37c388..1532725 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -32,8 +32,6 @@
 
 #include <assert.h>
 
-#ifdef __cplusplus
-
 #include <memory>
 #include <mutex>
 
@@ -46,7 +44,7 @@
  * construct this object is with SharedRefBase::make.
  */
 class SharedRefBase {
-public:
+   public:
     SharedRefBase() {}
     virtual ~SharedRefBase() {
         std::call_once(mFlagThis, [&]() {
@@ -83,7 +81,7 @@
         return t->template ref<T>();
     }
 
-private:
+   private:
     std::once_flag mFlagThis;
     std::weak_ptr<SharedRefBase> mThis;
 };
@@ -92,7 +90,7 @@
  * wrapper analog to IInterface
  */
 class ICInterface : public SharedRefBase {
-public:
+   public:
     ICInterface() {}
     virtual ~ICInterface() {}
 
@@ -113,7 +111,7 @@
  */
 template <typename INTERFACE>
 class BnCInterface : public INTERFACE {
-public:
+   public:
     BnCInterface() {}
     virtual ~BnCInterface() {}
 
@@ -121,15 +119,15 @@
 
     bool isRemote() override { return true; }
 
-protected:
+   protected:
     /**
      * This function should only be called by asBinder. Otherwise, there is a possibility of
      * multiple AIBinder* objects being created for the same instance of an object.
      */
     virtual SpAIBinder createBinder() = 0;
 
-private:
-    std::mutex mMutex; // for asBinder
+   private:
+    std::mutex mMutex;  // for asBinder
     ScopedAIBinder_Weak mWeakBinder;
 };
 
@@ -138,7 +136,7 @@
  */
 template <typename INTERFACE>
 class BpCInterface : public INTERFACE {
-public:
+   public:
     BpCInterface(const SpAIBinder& binder) : mBinder(binder) {}
     virtual ~BpCInterface() {}
 
@@ -146,7 +144,7 @@
 
     bool isRemote() override { return AIBinder_isRemote(mBinder.get()); }
 
-private:
+   private:
     SpAIBinder mBinder;
 };
 
@@ -171,8 +169,6 @@
     return mBinder;
 }
 
-} // namespace ndk
-
-#endif // __cplusplus
+}  // namespace ndk
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 0e97b50..2258210 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -47,27 +47,393 @@
 
 /**
  * Cleans up a parcel.
+ *
+ * \param parcel A parcel returned by AIBinder_prepareTransaction or AIBinder_transact when a
+ * transaction is being aborted.
  */
 void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29);
 
 /**
- * Writes an AIBinder to the next location in a non-null parcel. Can be null.
+ * Sets the position within the parcel.
+ *
+ * \param parcel The parcel of which to set the position.
+ * \param position Position of the parcel to set. This must be a value returned by
+ * AParcel_getDataPosition. Positions are constant for a given parcel between processes.
+ *
+ * \return STATUS_OK on success. If position is negative, then STATUS_BAD_VALUE will be returned.
+ */
+binder_status_t AParcel_setDataPosition(const AParcel* parcel, int32_t position)
+        __INTRODUCED_IN(29);
+
+/**
+ * Gets the current position within the parcel.
+ *
+ * \param parcel The parcel of which to get the position.
+ *
+ * \return The size of the parcel. This will always be greater than 0. The values returned by this
+ * function before and after calling various reads and writes are not defined. Only the delta
+ * between two positions between a specific sequence of calls is defined. For instance, if position
+ * is X, writeBool is called, and then position is Y, readBool can be called from position X will
+ * return the same value, and then position will be Y.
+ */
+int32_t AParcel_getDataPosition(const AParcel* parcel) __INTRODUCED_IN(29);
+
+/**
+ * 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. For a string, 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. However, if a 'null' string is being read, length will be -1.
+ *
+ * See also AParcel_readString.
+ *
+ * If allocation fails, null should be returned.
+ *
+ * \param stringData some external representation of a string
+ * \param length the length of the buffer needed to fill (including the null-terminator)
+ * \param buffer a buffer of size 'length' or null if allocation failed.
+ *
+ * \return true if the allocation succeeded, false otherwise. If length is -1, a true return here
+ * means that a 'null' value (or equivalent) was successfully stored.
+ */
+typedef bool (*AParcel_stringAllocator)(void* stringData, int32_t length, char** buffer);
+
+/**
+ * This is called to allocate an array of size 'length'. If length is -1, then a 'null' array (or
+ * equivalent) should be created.
+ *
+ * See also AParcel_readStringArray
+ *
+ * \param arrayData some external representation of an array
+ * \param length the length to allocate this array to
+ *
+ * \return true if allocation succeeded. If length is -1, a true return here means that a 'null'
+ * value (or equivalent) was successfully stored.
+ */
+typedef bool (*AParcel_stringArrayAllocator)(void* arrayData, int32_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. For a string, 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. However, if a 'null' string is being read, length will be -1.
+ *
+ * See also AParcel_readStringArray
+ *
+ * \param arrayData some external representation of an array.
+ * \param index the index at which a string should be allocated.
+ * \param length the length of the string to be allocated at this index. See also
+ * AParcel_stringAllocator. This includes the length required for a null-terminator.
+ * \param buffer a buffer of size 'length' or null if allocation failed.
+ *
+ * \return true if the allocation succeeded, false otherwise. If length is -1, a true return here
+ * means that a 'null' value (or equivalent) was successfully stored.
+ */
+typedef bool (*AParcel_stringArrayElementAllocator)(void* arrayData, size_t index, int32_t length,
+                                                    char** buffer);
+
+/**
+ * This returns the length and buffer of an array at a specific index in an arrayData object.
+ *
+ * See also AParcel_writeStringArray
+ *
+ * \param arrayData some external representation of an array.
+ * \param index the index at which a string should be allocated.
+ * \param outLength an out parameter for the length of the string at the specified index. This
+ * should not include the length for a null-terminator if there is one. If the object at this index
+ * is 'null', then this should be set to -1.
+ *
+ * \param a buffer of size outLength or more representing the string at the provided index. This is
+ * not required to be null-terminated. If the object at index is null, then this should be null.
+ */
+typedef const char* (*AParcel_stringArrayElementGetter)(const void* arrayData, size_t index,
+                                                        int32_t* outLength);
+
+/**
+ * This is called to allocate an array of size 'length'. If length is -1, then a 'null' array (or
+ * equivalent) should be created.
+ *
+ * See also AParcel_readParcelableArray
+ *
+ * \param arrayData some external representation of an array
+ * \param length the length to allocate this array to
+ *
+ * \return true if allocation succeeded. If length is -1, a true return here means that a 'null'
+ * value (or equivalent) was successfully stored.
+ */
+typedef bool (*AParcel_parcelableArrayAllocator)(void* arrayData, int32_t length);
+
+/**
+ * This is called to parcel the underlying data from an arrayData object at index.
+ *
+ * See also AParcel_writeParcelableArray
+ *
+ * \param parcel parcel to write the parcelable to
+ * \param arrayData some external representation of an array of parcelables (a user-defined type).
+ * \param index the index of the value to be retrieved.
+ *
+ * \return status (usually returned from other parceling functions). STATUS_OK for success.
+ */
+typedef binder_status_t (*AParcel_writeParcelableElement)(AParcel* parcel, const void* arrayData,
+                                                          size_t index);
+
+/**
+ * This is called to set an underlying value in an arrayData object at index.
+ *
+ * See also AParcel_readParcelableArray
+ *
+ * \param parcel parcel to read the parcelable from
+ * \param arrayData some external representation of an array of parcelables (a user-defined type).
+ * \param index the index of the value to be set.
+ *
+ * \return status (usually returned from other parceling functions). STATUS_OK for success.
+ */
+typedef binder_status_t (*AParcel_readParcelableElement)(const AParcel* parcel, void* arrayData,
+                                                         size_t index);
+
+// @START-PRIMITIVE-VECTOR-GETTERS
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * 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. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readInt32Array
+ *
+ * \param arrayData some external representation of an array of int32_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of int32_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_int32ArrayAllocator)(void* arrayData, int32_t length, int32_t** outBuffer);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * 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. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readUint32Array
+ *
+ * \param arrayData some external representation of an array of uint32_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of uint32_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_uint32ArrayAllocator)(void* arrayData, int32_t length, uint32_t** outBuffer);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * 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. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readInt64Array
+ *
+ * \param arrayData some external representation of an array of int64_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of int64_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_int64ArrayAllocator)(void* arrayData, int32_t length, int64_t** outBuffer);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * 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. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readUint64Array
+ *
+ * \param arrayData some external representation of an array of uint64_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of uint64_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_uint64ArrayAllocator)(void* arrayData, int32_t length, uint64_t** outBuffer);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * 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. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readFloatArray
+ *
+ * \param arrayData some external representation of an array of float.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of float of size 'length' (if length is >= 0, if length is 0, this may
+ * be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_floatArrayAllocator)(void* arrayData, int32_t length, float** outBuffer);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * 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. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readDoubleArray
+ *
+ * \param arrayData some external representation of an array of double.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of double of size 'length' (if length is >= 0, if length is 0, this may
+ * be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_doubleArrayAllocator)(void* arrayData, int32_t length, double** outBuffer);
+
+/**
+ * This allocates an array of size 'length' inside of arrayData and returns whether or not there was
+ * a success. If length is -1, then this should allocate some representation of a null array.
+ *
+ * See also AParcel_readBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param length the length to allocate arrayData to (or -1 if this represents a null array).
+ *
+ * \return whether the allocation succeeded.
+ */
+typedef bool (*AParcel_boolArrayAllocator)(void* arrayData, int32_t length);
+
+/**
+ * This is called to get the underlying data from an arrayData object at index.
+ *
+ * See also AParcel_writeBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param index the index of the value to be retrieved.
+ *
+ * \return the value of the array at index index.
+ */
+typedef bool (*AParcel_boolArrayGetter)(const void* arrayData, size_t index);
+
+/**
+ * This is called to set an underlying value in an arrayData object at index.
+ *
+ * See also AParcel_readBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param index the index of the value to be set.
+ * \param value the value to set at index index.
+ */
+typedef void (*AParcel_boolArraySetter)(void* arrayData, size_t index, bool value);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * 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. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readCharArray
+ *
+ * \param arrayData some external representation of an array of char16_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of char16_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_charArrayAllocator)(void* arrayData, int32_t length, char16_t** outBuffer);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * 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. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readByteArray
+ *
+ * \param arrayData some external representation of an array of int8_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of int8_t of size 'length' (if length is >= 0, if length is 0, this may
+ * be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_byteArrayAllocator)(void* arrayData, int32_t length, int8_t** outBuffer);
+
+// @END-PRIMITIVE-VECTOR-GETTERS
+
+/**
+ * Writes an AIBinder to the next location in a non-null parcel. Can be null. This does not take any
+ * refcounts of ownership of the binder from the client.
+ *
+ * \param parcel the parcel to write to.
+ * \param binder the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
- * Reads an AIBinder from the next location in a non-null parcel. This will fail if the binder is
- * non-null. One strong ref-count of ownership is passed to the caller of this function.
+ * Reads an AIBinder from the next location in a non-null parcel. One strong ref-count of ownership
+ * is passed to the caller of this function.
+ *
+ * \param parcel the parcel to read from.
+ * \param binder the out parameter for what is read from the parcel. This may be null.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder)
         __INTRODUCED_IN(29);
 
 /**
- * Reads an AIBinder from the next location in a non-null parcel. This may read a null. One strong
- * ref-count of ownership is passed to the caller of this function.
+ * Writes a file descriptor to the next location in a non-null parcel. This does not take ownership
+ * of fd.
+ *
+ * This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ *
+ * \param parcel the parcel to write to.
+ * \param fd the value to write to the parcel (-1 to represent a null ParcelFileDescriptor).
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder)
-        __INTRODUCED_IN(29);
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd);
+
+/**
+ * Reads an int from the next location in a non-null parcel.
+ *
+ * The returned fd must be closed.
+ *
+ * This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ *
+ * \param parcel the parcel to read from.
+ * \param fd the out parameter for what is read from the parcel (or -1 to represent a null
+ * ParcelFileDescriptor)
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd);
 
 /**
  * Writes an AStatus object to the next location in a non-null parcel.
@@ -77,6 +443,11 @@
  * status will be returned from this method and nothing will be written to the parcel. If either
  * this happens or if writing the status object itself fails, the return value from this function
  * should be propagated to the client, and AParcel_readStatusHeader shouldn't be called.
+ *
+ * \param parcel the parcel to write to.
+ * \param status the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status)
         __INTRODUCED_IN(29);
@@ -84,141 +455,566 @@
 /**
  * Reads an AStatus from the next location in a non-null parcel. Ownership is passed to the caller
  * of this function.
+ *
+ * \param parcel the parcel to read from.
+ * \param status the out parameter for what is read from the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status)
         __INTRODUCED_IN(29);
 
 /**
- * Writes string value to the next location in a non-null parcel.
+ * Writes utf-8 string value to the next location in a non-null parcel.
+ *
+ * If length is -1, and string is nullptr, this will write a 'null' string to the parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param string the null-terminated string to write to the parcel, at least of size 'length'.
+ * \param length the length of the string to be written.
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length)
+binder_status_t AParcel_writeString(AParcel* parcel, const char* string, int32_t length)
         __INTRODUCED_IN(29);
 
 /**
- * This is called to allocate a buffer
+ * Reads and allocates utf-8 string value from the next location in a non-null parcel.
  *
- * 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'.
+ * Data is passed to the string allocator once the string size is known. This size includes the
+ * space for the null-terminator of this string. This allocator returns a buffer which is used as
+ * the output buffer from this read. If there is a 'null' string on the binder buffer, the allocator
+ * will be called with length -1.
  *
- * If allocation fails, null should be returned.
+ * \param parcel the parcel to read from.
+ * \param stringData some external representation of a string.
+ * \param allocator allocator that will be called once the size of the string is known.
+ *
+ * \return STATUS_OK on successful write.
  */
-typedef void* (*AParcel_string_reallocator)(void* stringData, size_t length);
+binder_status_t AParcel_readString(const AParcel* parcel, void* stringData,
+                                   AParcel_stringAllocator allocator) __INTRODUCED_IN(29);
 
 /**
- * This is called to get the buffer from a stringData object.
- */
-typedef char* (*AParcel_string_getter)(void* stringData);
-
-/**
- * Reads and allocates string value from the next location in a non-null parcel.
+ * Writes utf-8 string array data to 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.
+ * 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. If length is -1,
+ * this will write a 'null' string array to the binder buffer.
  *
- * If this function returns a success, the buffer returned by allocator when passed stringData will
- * contain a null-terminated c-str read from the binder.
+ * \param parcel the parcel to write to.
+ * \param arrayData some external representation of an array.
+ * \param length the length of the array to be written.
+ * \param getter the callback that will be called for every index of the array to retrieve the
+ * corresponding string buffer.
+ *
+ * \return STATUS_OK on successful write.
  */
-binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_reallocator reallocator,
-                                   AParcel_string_getter getter, void** stringData)
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                         AParcel_stringArrayElementGetter getter)
         __INTRODUCED_IN(29);
 
-// @START
+/**
+ * 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. If the string array being read is 'null', this will
+ * instead just pass -1 to AParcel_stringArrayAllocator.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called with arrayData once the size of the output
+ * array is known.
+ * \param elementAllocator the callback that will be called on every index of arrayData to allocate
+ * the string at that location.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData,
+                                        AParcel_stringArrayAllocator allocator,
+                                        AParcel_stringArrayElementAllocator elementAllocator)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of parcelables (user-defined types) to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ * \param elementWriter function to be called for every array index to write the user-defined type
+ * at that location.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeParcelableArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                             AParcel_writeParcelableElement elementWriter)
+        __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of parcelables (user-defined types) 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, elementReader will be called for every index to read the
+ * corresponding parcelable.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ * \param elementReader the callback that will be called to fill out individual elements.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readParcelableArray(const AParcel* parcel, void* arrayData,
+                                            AParcel_parcelableArrayAllocator allocator,
+                                            AParcel_readParcelableElement elementReader)
+        __INTRODUCED_IN(29);
+
+// @START-PRIMITIVE-READ-WRITE
 /**
  * Writes int32_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes uint32_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes int64_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes uint64_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes float value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeFloat(AParcel* parcel, float value) __INTRODUCED_IN(29);
 
 /**
  * Writes double value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeDouble(AParcel* parcel, double value) __INTRODUCED_IN(29);
 
 /**
  * Writes bool value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeBool(AParcel* parcel, bool value) __INTRODUCED_IN(29);
 
 /**
  * Writes char16_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes int8_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
  */
 binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value) __INTRODUCED_IN(29);
 
 /**
  * Reads into int32_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into uint32_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into int64_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into uint64_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into float value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readFloat(const AParcel* parcel, float* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into double value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readDouble(const AParcel* parcel, double* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into bool value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readBool(const AParcel* parcel, bool* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into char16_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into int8_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
  */
 binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) __INTRODUCED_IN(29);
 
-// @END
+/**
+ * Writes an array of int32_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
 
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+/**
+ * Writes an array of uint32_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of int64_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of uint64_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of float to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of double to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of bool to the next location in a non-null parcel.
+ *
+ * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying
+ * values to write to the parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData some external representation of an array.
+ * \param length the length of arrayData (or -1 if this represents a null array).
+ * \param getter the callback to retrieve data at specific locations in the array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                       AParcel_boolArrayGetter getter) __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of char16_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of int8_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of int32_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData,
+                                       AParcel_int32ArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of uint32_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData,
+                                        AParcel_uint32ArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of int64_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData,
+                                       AParcel_int64ArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of uint64_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData,
+                                        AParcel_uint64ArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of float from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData,
+                                       AParcel_floatArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of double from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData,
+                                        AParcel_doubleArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of bool from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. Then, for every i in [0, length),
+ * setter(arrayData, i, x) will be called where x is the value at the associated index.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ * \param setter the callback that will be called to set a value at a specific location in the
+ * array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_boolArrayAllocator allocator,
+                                      AParcel_boolArraySetter setter) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of char16_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_charArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of int8_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_byteArrayAllocator allocator) __INTRODUCED_IN(29);
+
+// @END-PRIMITIVE-READ-WRITE
+
+#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
index d3e6cae..f3bc31b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -26,30 +26,319 @@
 
 #pragma once
 
+#include <android/binder_auto_utils.h>
 #include <android/binder_parcel.h>
 
-#ifdef __cplusplus
-
+#include <optional>
 #include <string>
+#include <vector>
 
 namespace ndk {
 
 /**
- * Takes a std::string and reallocates it to the specified length. For use with AParcel_readString.
- * See use below in AParcel_readString.
+ * This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
  */
-static inline void* AParcel_std_string_reallocator(void* stringData, size_t length) {
-    std::string* str = static_cast<std::string*>(stringData);
-    str->resize(length - 1);
-    return stringData;
+template <typename T>
+static inline bool AParcel_stdVectorAllocator(void* vectorData, int32_t length, T** outBuffer) {
+    if (length < 0) return false;
+
+    std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
+    if (static_cast<size_t>(length) > vec->max_size()) return false;
+
+    vec->resize(length);
+    *outBuffer = vec->data();
+    return true;
 }
 
 /**
- * Takes a std::string and returns the inner char*.
+ * This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
  */
-static inline char* AParcel_std_string_getter(void* stringData) {
+template <typename T>
+static inline bool AParcel_nullableStdVectorAllocator(void* vectorData, int32_t length,
+                                                      T** outBuffer) {
+    std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData);
+
+    if (length < 0) {
+        *vec = std::nullopt;
+        return true;
+    }
+
+    *vec = std::optional<std::vector<T>>(std::vector<T>{});
+
+    if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
+    (*vec)->resize(length);
+
+    *outBuffer = (*vec)->data();
+    return true;
+}
+
+/**
+ * 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. Note that when this allocator is used,
+ * null arrays are not supported.
+ *
+ * See AParcel_readVector(const AParcel* parcel, std::vector<bool>)
+ * See AParcel_readVector(const AParcel* parcel, std::vector<std::string>)
+ */
+template <typename T>
+static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, int32_t length) {
+    if (length < 0) return false;
+
+    std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
+    if (static_cast<size_t>(length) > vec->max_size()) return false;
+
+    vec->resize(length);
+    return true;
+}
+
+/**
+ * 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. Note, when this allocator is used,
+ * the vector itself can be nullable.
+ *
+ * See AParcel_readVector(const AParcel* parcel,
+ * std::optional<std::vector<std::optional<std::string>>>)
+ */
+template <typename T>
+static inline bool AParcel_nullableStdVectorExternalAllocator(void* vectorData, int32_t length) {
+    std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData);
+
+    if (length < 0) {
+        *vec = std::nullopt;
+        return true;
+    }
+
+    *vec = std::optional<std::vector<T>>(std::vector<T>{});
+
+    if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
+    (*vec)->resize(length);
+
+    return true;
+}
+
+/**
+ * This retrieves the underlying value in a vector which may not be contiguous at index from a
+ * corresponding vectorData.
+ */
+template <typename T>
+static inline T AParcel_stdVectorGetter(const void* vectorData, size_t index) {
+    const std::vector<T>* vec = static_cast<const std::vector<T>*>(vectorData);
+    return (*vec)[index];
+}
+
+/**
+ * This sets the underlying value in a corresponding vectorData which may not be contiguous at
+ * index.
+ */
+template <typename T>
+static inline void AParcel_stdVectorSetter(void* vectorData, size_t index, T value) {
+    std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
+    (*vec)[index] = value;
+}
+
+/**
+ * This sets the underlying value in a corresponding vectorData which may not be contiguous at
+ * index.
+ */
+template <typename T>
+static inline void AParcel_nullableStdVectorSetter(void* vectorData, size_t index, T value) {
+    std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData);
+    vec->value()[index] = value;
+}
+
+/**
+ * Convenience method to write a nullable strong binder.
+ */
+static inline binder_status_t AParcel_writeNullableStrongBinder(AParcel* parcel,
+                                                                const SpAIBinder& binder) {
+    return AParcel_writeStrongBinder(parcel, binder.get());
+}
+
+/**
+ * Convenience method to read a nullable strong binder.
+ */
+static inline binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel,
+                                                               SpAIBinder* binder) {
+    AIBinder* readBinder;
+    binder_status_t status = AParcel_readStrongBinder(parcel, &readBinder);
+    if (status == STATUS_OK) {
+        binder->set(readBinder);
+    }
+    return status;
+}
+
+/**
+ * Convenience method to write a strong binder but return an error if it is null.
+ */
+static inline binder_status_t AParcel_writeRequiredStrongBinder(AParcel* parcel,
+                                                                const SpAIBinder& binder) {
+    if (binder.get() == nullptr) {
+        return STATUS_UNEXPECTED_NULL;
+    }
+    return AParcel_writeStrongBinder(parcel, binder.get());
+}
+
+/**
+ * Convenience method to read a strong binder but return an error if it is null.
+ */
+static inline binder_status_t AParcel_readRequiredStrongBinder(const AParcel* parcel,
+                                                               SpAIBinder* binder) {
+    AIBinder* readBinder;
+    binder_status_t ret = AParcel_readStrongBinder(parcel, &readBinder);
+    if (ret == STATUS_OK) {
+        if (readBinder == nullptr) {
+            return STATUS_UNEXPECTED_NULL;
+        }
+
+        binder->set(readBinder);
+    }
+    return ret;
+}
+
+/**
+ * Convenience method to write a ParcelFileDescriptor where -1 represents a null value.
+ */
+static inline binder_status_t AParcel_writeNullableParcelFileDescriptor(
+        AParcel* parcel, const ScopedFileDescriptor& fd) {
+    return AParcel_writeParcelFileDescriptor(parcel, fd.get());
+}
+
+/**
+ * Convenience method to read a ParcelFileDescriptor where -1 represents a null value.
+ */
+static inline binder_status_t AParcel_readNullableParcelFileDescriptor(const AParcel* parcel,
+                                                                       ScopedFileDescriptor* fd) {
+    int readFd;
+    binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd);
+    if (status == STATUS_OK) {
+        fd->set(readFd);
+    }
+    return status;
+}
+
+/**
+ * Convenience method to write a valid ParcelFileDescriptor.
+ */
+static inline binder_status_t AParcel_writeRequiredParcelFileDescriptor(
+        AParcel* parcel, const ScopedFileDescriptor& fd) {
+    if (fd.get() < 0) {
+        return STATUS_UNEXPECTED_NULL;
+    }
+    return AParcel_writeParcelFileDescriptor(parcel, fd.get());
+}
+
+/**
+ * Convenience method to read a valid ParcelFileDescriptor.
+ */
+static inline binder_status_t AParcel_readRequiredParcelFileDescriptor(const AParcel* parcel,
+                                                                       ScopedFileDescriptor* fd) {
+    int readFd;
+    binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd);
+    if (status == STATUS_OK) {
+        if (readFd < 0) {
+            return STATUS_UNEXPECTED_NULL;
+        }
+        fd->set(readFd);
+    }
+    return status;
+}
+
+/**
+ * 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 bool AParcel_stdStringAllocator(void* stringData, int32_t length, char** buffer) {
+    if (length <= 0) return false;
+
     std::string* str = static_cast<std::string*>(stringData);
-    return &(*str)[0];
+    str->resize(length - 1);
+    *buffer = &(*str)[0];
+    return true;
+}
+
+/**
+ * Allocates a string in a std::optional<std::string> to size 'length' (or to std::nullopt when
+ * length is -1) and returns the underlying buffer. For use with AParcel_readString. See use below
+ * in AParcel_readString(const AParcel*, std::optional<std::string>*).
+ */
+static inline bool AParcel_nullableStdStringAllocator(void* stringData, int32_t length,
+                                                      char** buffer) {
+    if (length == 0) return false;
+
+    std::optional<std::string>* str = static_cast<std::optional<std::string>*>(stringData);
+
+    if (length < 0) {
+        *str = std::nullopt;
+        return true;
+    }
+
+    *str = std::optional<std::string>(std::string{});
+    (*str)->resize(length - 1);
+    *buffer = &(**str)[0];
+    return true;
+}
+
+/**
+ * Allocates a std::string inside of a std::vector<std::string> at index 'index' to size 'length'.
+ */
+static inline bool AParcel_stdVectorStringElementAllocator(void* vectorData, size_t index,
+                                                           int32_t length, char** buffer) {
+    std::vector<std::string>* vec = static_cast<std::vector<std::string>*>(vectorData);
+    std::string& element = vec->at(index);
+    return AParcel_stdStringAllocator(static_cast<void*>(&element), length, buffer);
+}
+
+/**
+ * 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,
+                                                               int32_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();
+}
+
+/**
+ * Allocates a string in a std::optional<std::string> inside of a
+ * std::optional<std::vector<std::optional<std::string>>> at index 'index' to size 'length' (or to
+ * std::nullopt when length is -1).
+ */
+static inline bool AParcel_nullableStdVectorStringElementAllocator(void* vectorData, size_t index,
+                                                                   int32_t length, char** buffer) {
+    std::optional<std::vector<std::optional<std::string>>>* vec =
+            static_cast<std::optional<std::vector<std::optional<std::string>>>*>(vectorData);
+    std::optional<std::string>& element = vec->value().at(index);
+    return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer);
+}
+
+/**
+ * This gets the length and buffer of a std::optional<std::string> inside of a
+ * std::vector<std::string> at index index. If the string is null, then it returns null and a length
+ * of -1.
+ */
+static inline const char* AParcel_nullableStdVectorStringElementGetter(const void* vectorData,
+                                                                       size_t index,
+                                                                       int32_t* outLength) {
+    const std::optional<std::vector<std::optional<std::string>>>* vec =
+            static_cast<const std::optional<std::vector<std::optional<std::string>>>*>(vectorData);
+    const std::optional<std::string>& element = vec->value().at(index);
+
+    if (!element) {
+        *outLength = -1;
+        return nullptr;
+    }
+
+    *outLength = element->size();
+    return element->c_str();
 }
 
 /**
@@ -64,12 +353,485 @@
  */
 static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) {
     void* stringData = static_cast<void*>(str);
-    return AParcel_readString(parcel, AParcel_std_string_reallocator, AParcel_std_string_getter,
-                              &stringData);
+    return AParcel_readString(parcel, stringData, AParcel_stdStringAllocator);
 }
 
-} // namespace ndk
+/**
+ * Convenience API for writing a std::optional<std::string>.
+ */
+static inline binder_status_t AParcel_writeString(AParcel* parcel,
+                                                  const std::optional<std::string>& str) {
+    if (!str) {
+        return AParcel_writeString(parcel, nullptr, -1);
+    }
 
-#endif // __cplusplus
+    return AParcel_writeString(parcel, str->c_str(), str->size());
+}
+
+/**
+ * Convenience API for reading a std::optional<std::string>.
+ */
+static inline binder_status_t AParcel_readString(const AParcel* parcel,
+                                                 std::optional<std::string>* str) {
+    void* stringData = static_cast<void*>(str);
+    return AParcel_readString(parcel, stringData, AParcel_nullableStdStringAllocator);
+}
+
+/**
+ * Convenience API for writing a std::vector<std::string>
+ */
+static inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                                  const std::vector<std::string>& vec) {
+    const void* vectorData = static_cast<const void*>(&vec);
+    return AParcel_writeStringArray(parcel, vectorData, vec.size(),
+                                    AParcel_stdVectorStringElementGetter);
+}
+
+/**
+ * Convenience API for reading a std::vector<std::string>
+ */
+static inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                                 std::vector<std::string>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readStringArray(parcel, vectorData,
+                                   AParcel_stdVectorExternalAllocator<std::string>,
+                                   AParcel_stdVectorStringElementAllocator);
+}
+
+/**
+ * Convenience API for writing a std::optional<std::vector<std::optional<std::string>>>
+ */
+static inline binder_status_t AParcel_writeVector(
+        AParcel* parcel, const std::optional<std::vector<std::optional<std::string>>>& vec) {
+    const void* vectorData = static_cast<const void*>(&vec);
+    return AParcel_writeStringArray(parcel, vectorData, (vec ? vec->size() : -1),
+                                    AParcel_nullableStdVectorStringElementGetter);
+}
+
+/**
+ * Convenience API for reading a std::optional<std::vector<std::optional<std::string>>>
+ */
+static inline binder_status_t AParcel_readVector(
+        const AParcel* parcel, std::optional<std::vector<std::optional<std::string>>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readStringArray(
+            parcel, vectorData,
+            AParcel_nullableStdVectorExternalAllocator<std::optional<std::string>>,
+            AParcel_nullableStdVectorStringElementAllocator);
+}
+
+/**
+ * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
+ */
+template <typename P>
+binder_status_t AParcel_writeStdVectorParcelableElement(AParcel* parcel, const void* vectorData,
+                                                        size_t index) {
+    const std::vector<P>* vector = static_cast<const std::vector<P>*>(vectorData);
+    return vector->at(index).writeToParcel(parcel);
+}
+
+/**
+ * Reads a parcelable object of type P inside a std::vector<P> at index 'index' from 'parcel'.
+ */
+template <typename P>
+binder_status_t AParcel_readStdVectorParcelableElement(const AParcel* parcel, void* vectorData,
+                                                       size_t index) {
+    std::vector<P>* vector = static_cast<std::vector<P>*>(vectorData);
+    return vector->at(index).readFromParcel(parcel);
+}
+
+/**
+ * Convenience API for writing a std::vector<P>
+ */
+template <typename P>
+static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<P>& vec) {
+    const void* vectorData = static_cast<const void*>(&vec);
+    return AParcel_writeParcelableArray(parcel, vectorData, vec.size(),
+                                        AParcel_writeStdVectorParcelableElement<P>);
+}
+
+/**
+ * Convenience API for reading a std::vector<P>
+ */
+template <typename P>
+static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<P>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readParcelableArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<P>,
+                                       AParcel_readStdVectorParcelableElement<P>);
+}
+
+// @START
+/**
+ * Writes a vector of int32_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) {
+    return AParcel_writeInt32Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of int32_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<int32_t>>& vec) {
+    if (!vec) return AParcel_writeInt32Array(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of int32_t from the next location in a non-null parcel.
+ */
+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_stdVectorAllocator<int32_t>);
+}
+
+/**
+ * Reads an optional vector of int32_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<int32_t>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readInt32Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int32_t>);
+}
+
+/**
+ * Writes a vector of uint32_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) {
+    return AParcel_writeUint32Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of uint32_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<uint32_t>>& vec) {
+    if (!vec) return AParcel_writeUint32Array(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of uint32_t from the next location in a non-null parcel.
+ */
+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_stdVectorAllocator<uint32_t>);
+}
+
+/**
+ * Reads an optional vector of uint32_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<uint32_t>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readUint32Array(parcel, vectorData,
+                                   AParcel_nullableStdVectorAllocator<uint32_t>);
+}
+
+/**
+ * Writes a vector of int64_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) {
+    return AParcel_writeInt64Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of int64_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<int64_t>>& vec) {
+    if (!vec) return AParcel_writeInt64Array(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of int64_t from the next location in a non-null parcel.
+ */
+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_stdVectorAllocator<int64_t>);
+}
+
+/**
+ * Reads an optional vector of int64_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<int64_t>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readInt64Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int64_t>);
+}
+
+/**
+ * Writes a vector of uint64_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) {
+    return AParcel_writeUint64Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of uint64_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<uint64_t>>& vec) {
+    if (!vec) return AParcel_writeUint64Array(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of uint64_t from the next location in a non-null parcel.
+ */
+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_stdVectorAllocator<uint64_t>);
+}
+
+/**
+ * Reads an optional vector of uint64_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<uint64_t>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readUint64Array(parcel, vectorData,
+                                   AParcel_nullableStdVectorAllocator<uint64_t>);
+}
+
+/**
+ * Writes a vector of float to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) {
+    return AParcel_writeFloatArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of float to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<float>>& vec) {
+    if (!vec) return AParcel_writeFloatArray(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of float from the next location in a non-null parcel.
+ */
+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_stdVectorAllocator<float>);
+}
+
+/**
+ * Reads an optional vector of float from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<float>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readFloatArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<float>);
+}
+
+/**
+ * Writes a vector of double to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) {
+    return AParcel_writeDoubleArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of double to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<double>>& vec) {
+    if (!vec) return AParcel_writeDoubleArray(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of double from the next location in a non-null parcel.
+ */
+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_stdVectorAllocator<double>);
+}
+
+/**
+ * Reads an optional vector of double from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<double>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readDoubleArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<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), vec.size(),
+                                  AParcel_stdVectorGetter<bool>);
+}
+
+/**
+ * Writes an optional vector of bool to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<bool>>& vec) {
+    if (!vec) return AParcel_writeBoolArray(parcel, nullptr, -1, AParcel_stdVectorGetter<bool>);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of bool from the next location in a non-null parcel.
+ */
+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_stdVectorExternalAllocator<bool>,
+                                 AParcel_stdVectorSetter<bool>);
+}
+
+/**
+ * Reads an optional vector of bool from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<bool>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readBoolArray(parcel, vectorData,
+                                 AParcel_nullableStdVectorExternalAllocator<bool>,
+                                 AParcel_nullableStdVectorSetter<bool>);
+}
+
+/**
+ * Writes a vector of char16_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) {
+    return AParcel_writeCharArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of char16_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<char16_t>>& vec) {
+    if (!vec) return AParcel_writeCharArray(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of char16_t from the next location in a non-null parcel.
+ */
+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_stdVectorAllocator<char16_t>);
+}
+
+/**
+ * Reads an optional vector of char16_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<char16_t>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readCharArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<char16_t>);
+}
+
+/**
+ * Writes a vector of int8_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int8_t>& vec) {
+    return AParcel_writeByteArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of int8_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<int8_t>>& vec) {
+    if (!vec) return AParcel_writeByteArray(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of int8_t from the next location in a non-null parcel.
+ */
+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_stdVectorAllocator<int8_t>);
+}
+
+/**
+ * Reads an optional vector of int8_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<int8_t>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readByteArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<int8_t>);
+}
+
+// @END
+
+/**
+ * Convenience API for writing the size of a vector.
+ */
+template <typename T>
+static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, const std::vector<T>& vec) {
+    if (vec.size() > INT32_MAX) {
+        return STATUS_BAD_VALUE;
+    }
+
+    return AParcel_writeInt32(parcel, static_cast<int32_t>(vec.size()));
+}
+
+/**
+ * Convenience API for writing the size of a vector.
+ */
+template <typename T>
+static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel,
+                                                      const std::optional<std::vector<T>>& vec) {
+    if (!vec) {
+        return AParcel_writeInt32(parcel, -1);
+    }
+
+    if (vec->size() > INT32_MAX) {
+        return STATUS_BAD_VALUE;
+    }
+
+    return AParcel_writeInt32(parcel, static_cast<int32_t>(vec->size()));
+}
+
+/**
+ * Convenience API for resizing a vector.
+ */
+template <typename T>
+static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, std::vector<T>* vec) {
+    int32_t size;
+    binder_status_t err = AParcel_readInt32(parcel, &size);
+
+    if (err != STATUS_OK) return err;
+    if (size < 0) return STATUS_UNEXPECTED_NULL;
+
+    vec->resize(static_cast<size_t>(size));
+    return STATUS_OK;
+}
+
+/**
+ * Convenience API for resizing a vector.
+ */
+template <typename T>
+static inline binder_status_t AParcel_resizeVector(const AParcel* parcel,
+                                                   std::optional<std::vector<T>>* vec) {
+    int32_t size;
+    binder_status_t err = AParcel_readInt32(parcel, &size);
+
+    if (err != STATUS_OK) return err;
+    if (size < -1) return STATUS_UNEXPECTED_NULL;
+
+    if (size == -1) {
+        *vec = std::nullopt;
+        return STATUS_OK;
+    }
+
+    *vec = std::optional<std::vector<T>>(std::vector<T>{});
+    (*vec)->resize(static_cast<size_t>(size));
+    return STATUS_OK;
+}
+
+}  // namespace ndk
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index 2d8b7fa..2671b9b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -35,7 +35,7 @@
 enum {
     STATUS_OK = 0,
 
-    STATUS_UNKNOWN_ERROR = (-2147483647 - 1), // INT32_MIN value
+    STATUS_UNKNOWN_ERROR = (-2147483647 - 1),  // INT32_MIN value
     STATUS_NO_MEMORY = -ENOMEM,
     STATUS_INVALID_OPERATION = -ENOSYS,
     STATUS_BAD_VALUE = -EINVAL,
@@ -95,24 +95,39 @@
  * along with service specific errors.
  *
  * It is not required to be used in order to parcel/receive transactions, but it is required in
- * order to be compatible with standard AIDL transactions.
+ * order to be compatible with standard AIDL transactions since it is written as the header to the
+ * out parcel for transactions which get executed (don't fail during unparceling of input arguments
+ * or sooner).
  */
 struct AStatus;
 typedef struct AStatus AStatus;
 
 /**
  * New status which is considered a success.
+ *
+ * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29);
 
 /**
  * New status with exception code.
+ *
+ * \param exception the code that this status should represent. If this is EX_NONE, then this
+ * constructs an non-error status object.
+ *
+ * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCode(binder_exception_t exception)
         __INTRODUCED_IN(29);
 
 /**
  * New status with exception code and message.
+ *
+ * \param exception the code that this status should represent. If this is EX_NONE, then this
+ * constructs an non-error status object.
+ * \param message the error message to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCodeWithMessage(
         binder_exception_t exception, const char* message) __INTRODUCED_IN(29);
@@ -121,6 +136,10 @@
  * New status with a service speciic error.
  *
  * This is considered to be EX_TRANSACTION_FAILED with extra information.
+ *
+ * \param serviceSpecific an implementation defined error code.
+ *
+ * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificError(
         int32_t serviceSpecific) __INTRODUCED_IN(29);
@@ -129,6 +148,11 @@
  * New status with a service specific error and message.
  *
  * This is considered to be EX_TRANSACTION_FAILED with extra information.
+ *
+ * \param serviceSpecific an implementation defined error code.
+ * \param message the error message to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificErrorWithMessage(
         int32_t serviceSpecific, const char* message) __INTRODUCED_IN(29);
@@ -137,6 +161,10 @@
  * New status with binder_status_t. This is typically for low level failures when a binder_status_t
  * is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning
  * an AStatus instance.
+ *
+ * \param a low-level error to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromStatus(binder_status_t status)
         __INTRODUCED_IN(29);
@@ -144,11 +172,19 @@
 /**
  * Whether this object represents a successful transaction. If this function returns true, then
  * AStatus_getExceptionCode will return EX_NONE.
+ *
+ * \param status the status being queried.
+ *
+ * \return whether the status represents a successful transaction. For more details, see below.
  */
 bool AStatus_isOk(const AStatus* status) __INTRODUCED_IN(29);
 
 /**
  * The exception that this status object represents.
+ *
+ * \param status the status being queried.
+ *
+ * \return the exception code that this object represents.
  */
 binder_exception_t AStatus_getExceptionCode(const AStatus* status) __INTRODUCED_IN(29);
 
@@ -157,6 +193,10 @@
  * non-zero result if AStatus_getExceptionCode returns EX_SERVICE_SPECIFIC. If this function returns
  * 0, the status object may still represent a different exception or status. To find out if this
  * transaction as a whole is okay, use AStatus_isOk instead.
+ *
+ * \param status the status being queried.
+ *
+ * \return the service-specific error code if the exception code is EX_SERVICE_SPECIFIC or 0.
  */
 int32_t AStatus_getServiceSpecificError(const AStatus* status) __INTRODUCED_IN(29);
 
@@ -165,6 +205,10 @@
  * if AStatus_getExceptionCode returns EX_TRANSACTION_FAILED. If this function return 0, the status
  * object may represent a different exception or a service specific error. To find out if this
  * transaction as a whole is okay, use AStatus_isOk instead.
+ *
+ * \param status the status being queried.
+ *
+ * \return the status code if the exception code is EX_TRANSACTION_FAILED or 0.
  */
 binder_status_t AStatus_getStatus(const AStatus* status) __INTRODUCED_IN(29);
 
@@ -173,15 +217,21 @@
  * message, this will return an empty string.
  *
  * The returned string has the lifetime of the status object passed into this function.
+ *
+ * \param status the status being queried.
+ *
+ * \return the message associated with this error.
  */
 const char* AStatus_getMessage(const AStatus* status) __INTRODUCED_IN(29);
 
 /**
  * Deletes memory associated with the status instance.
+ *
+ * \param status the status to delete, returned from AStatus_newOk or one of the AStatus_from* APIs.
  */
 void AStatus_delete(AStatus* status) __INTRODUCED_IN(29);
 
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 2a1bff1..ee7132f 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -7,6 +7,8 @@
     AIBinder_debugGetRefCount;
     AIBinder_decStrong;
     AIBinder_fromJavaBinder;
+    AIBinder_getCallingPid;
+    AIBinder_getCallingUid;
     AIBinder_getClass;
     AIBinder_getUserData;
     AIBinder_incStrong;
@@ -23,31 +25,56 @@
     AIBinder_Weak_new;
     AIBinder_Weak_promote;
     AParcel_delete;
+    AParcel_getDataPosition;
     AParcel_readBool;
+    AParcel_readBoolArray;
     AParcel_readByte;
+    AParcel_readByteArray;
     AParcel_readChar;
+    AParcel_readCharArray;
     AParcel_readDouble;
+    AParcel_readDoubleArray;
     AParcel_readFloat;
+    AParcel_readFloatArray;
     AParcel_readInt32;
+    AParcel_readInt32Array;
     AParcel_readInt64;
-    AParcel_readNullableStrongBinder;
+    AParcel_readInt64Array;
+    AParcel_readParcelableArray;
+    AParcel_readParcelFileDescriptor;
     AParcel_readStatusHeader;
     AParcel_readString;
+    AParcel_readStringArray;
     AParcel_readStrongBinder;
     AParcel_readUint32;
+    AParcel_readUint32Array;
     AParcel_readUint64;
+    AParcel_readUint64Array;
+    AParcel_setDataPosition;
     AParcel_writeBool;
+    AParcel_writeBoolArray;
     AParcel_writeByte;
+    AParcel_writeByteArray;
     AParcel_writeChar;
+    AParcel_writeCharArray;
     AParcel_writeDouble;
+    AParcel_writeDoubleArray;
     AParcel_writeFloat;
+    AParcel_writeFloatArray;
     AParcel_writeInt32;
+    AParcel_writeInt32Array;
     AParcel_writeInt64;
+    AParcel_writeInt64Array;
+    AParcel_writeParcelableArray;
+    AParcel_writeParcelFileDescriptor;
     AParcel_writeStatusHeader;
     AParcel_writeString;
+    AParcel_writeStringArray;
     AParcel_writeStrongBinder;
     AParcel_writeUint32;
+    AParcel_writeUint32Array;
     AParcel_writeUint64;
+    AParcel_writeUint64Array;
     AStatus_delete;
     AStatus_fromExceptionCode;
     AStatus_fromExceptionCodeWithMessage;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 3e03e90..ae2276e 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -23,35 +23,214 @@
 #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 ContiguousArrayAllocator = bool (*)(void* arrayData, int32_t length, T** outBuffer);
+
+template <typename T>
+using ArrayAllocator = bool (*)(void* arrayData, int32_t length);
+template <typename T>
+using ArrayGetter = T (*)(const void* arrayData, size_t index);
+template <typename T>
+using ArraySetter = void (*)(void* arrayData, size_t index, T value);
+
+binder_status_t WriteAndValidateArraySize(AParcel* parcel, bool isNullArray, int32_t length) {
+    // only -1 can be used to represent a null array
+    if (length < -1) return STATUS_BAD_VALUE;
+
+    if (!isNullArray && length < 0) {
+        LOG(ERROR) << __func__ << ": null array must be used with length == -1.";
+        return STATUS_BAD_VALUE;
+    }
+    if (isNullArray && length > 0) {
+        LOG(ERROR) << __func__ << ": null buffer cannot be for size " << length << " array.";
+        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);
+
+    return STATUS_OK;
+}
+
+template <typename T>
+binder_status_t WriteArray(AParcel* parcel, const T* array, int32_t length) {
+    binder_status_t status = WriteAndValidateArraySize(parcel, array == nullptr, length);
+    if (status != STATUS_OK) return status;
+    if (length <= 0) return STATUS_OK;
+
+    int32_t size = 0;
+    if (__builtin_smul_overflow(sizeof(T), length, &size)) return STATUS_NO_MEMORY;
+
+    void* const data = parcel->get()->writeInplace(size);
+    if (data == nullptr) return STATUS_NO_MEMORY;
+
+    memcpy(data, array, size);
+
+    return STATUS_OK;
+}
+
+// Each element in a char16_t array is converted to an int32_t (not packed).
+template <>
+binder_status_t WriteArray<char16_t>(AParcel* parcel, const char16_t* array, int32_t length) {
+    binder_status_t status = WriteAndValidateArraySize(parcel, array == nullptr, length);
+    if (status != STATUS_OK) return status;
+    if (length <= 0) return STATUS_OK;
+
+    int32_t size = 0;
+    if (__builtin_smul_overflow(sizeof(char16_t), length, &size)) return STATUS_NO_MEMORY;
+
+    Parcel* rawParcel = parcel->get();
+
+    for (int32_t i = 0; i < length; i++) {
+        status = rawParcel->writeChar(array[i]);
+
+        if (status != STATUS_OK) return PruneStatusT(status);
+    }
+
+    return STATUS_OK;
+}
+
+template <typename T>
+binder_status_t ReadArray(const AParcel* parcel, void* arrayData,
+                          ContiguousArrayAllocator<T> allocator) {
+    const Parcel* rawParcel = parcel->get();
+
+    int32_t length;
+    status_t status = rawParcel->readInt32(&length);
+
+    if (status != STATUS_OK) return PruneStatusT(status);
+    if (length < -1) return STATUS_BAD_VALUE;
+
+    T* array;
+    if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+
+    if (length <= 0) return STATUS_OK;
+    if (array == nullptr) return STATUS_NO_MEMORY;
+
+    int32_t size = 0;
+    if (__builtin_smul_overflow(sizeof(T), length, &size)) return STATUS_NO_MEMORY;
+
+    const void* data = rawParcel->readInplace(size);
+    if (data == nullptr) return STATUS_NO_MEMORY;
+
+    memcpy(array, data, size);
+
+    return STATUS_OK;
+}
+
+// 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,
+                                    ContiguousArrayAllocator<char16_t> allocator) {
+    const Parcel* rawParcel = parcel->get();
+
+    int32_t length;
+    status_t status = rawParcel->readInt32(&length);
+
+    if (status != STATUS_OK) return PruneStatusT(status);
+    if (length < -1) return STATUS_BAD_VALUE;
+
+    char16_t* array;
+    if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+
+    if (length <= 0) return STATUS_OK;
+    if (array == nullptr) return STATUS_NO_MEMORY;
+
+    int32_t size = 0;
+    if (__builtin_smul_overflow(sizeof(char16_t), length, &size)) return STATUS_NO_MEMORY;
+
+    for (int32_t i = 0; i < length; i++) {
+        status = rawParcel->readChar(array + i);
+
+        if (status != STATUS_OK) return PruneStatusT(status);
+    }
+
+    return STATUS_OK;
+}
+
+template <typename T>
+binder_status_t WriteArray(AParcel* parcel, const void* arrayData, int32_t length,
+                           ArrayGetter<T> getter, status_t (Parcel::*write)(T)) {
+    // we have no clue if arrayData represents a null object or not, we can only infer from length
+    bool arrayIsNull = length < 0;
+    binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length);
+    if (status != STATUS_OK) return status;
+    if (length <= 0) return STATUS_OK;
+
+    Parcel* rawParcel = parcel->get();
+
+    for (int32_t i = 0; i < length; i++) {
+        status = (rawParcel->*write)(getter(arrayData, i));
+
+        if (status != STATUS_OK) return PruneStatusT(status);
+    }
+
+    return STATUS_OK;
+}
+
+template <typename T>
+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;
+    status_t status = rawParcel->readInt32(&length);
+
+    if (status != STATUS_OK) return PruneStatusT(status);
+    if (length < -1) return STATUS_BAD_VALUE;
+
+    if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+
+    if (length <= 0) return STATUS_OK;
+
+    for (int32_t i = 0; i < length; i++) {
+        T readTarget;
+        status = (rawParcel->*read)(&readTarget);
+        if (status != STATUS_OK) return PruneStatusT(status);
+
+        setter(arrayData, i, readTarget);
+    }
+
+    return STATUS_OK;
+}
 
 void AParcel_delete(AParcel* parcel) {
     delete parcel;
 }
 
+binder_status_t AParcel_setDataPosition(const AParcel* parcel, int32_t position) {
+    if (position < 0) {
+        return STATUS_BAD_VALUE;
+    }
+
+    parcel->get()->setDataPosition(position);
+    return STATUS_OK;
+}
+
+int32_t AParcel_getDataPosition(const AParcel* parcel) {
+    return parcel->get()->dataPosition();
+}
+
 binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) {
     sp<IBinder> writeBinder = binder != nullptr ? binder->getBinder() : nullptr;
     return parcel->get()->writeStrongBinder(writeBinder);
 }
 binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder) {
     sp<IBinder> readBinder = nullptr;
-    status_t status = parcel->get()->readStrongBinder(&readBinder);
-    if (status != STATUS_OK) {
-        return PruneStatusT(status);
-    }
-    sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(readBinder);
-    AIBinder_incStrong(ret.get());
-    *binder = ret.get();
-    return PruneStatusT(status);
-}
-binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder) {
-    sp<IBinder> readBinder = nullptr;
     status_t status = parcel->get()->readNullableStrongBinder(&readBinder);
     if (status != STATUS_OK) {
         return PruneStatusT(status);
@@ -61,21 +240,73 @@
     *binder = ret.get();
     return PruneStatusT(status);
 }
+
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) {
+    std::unique_ptr<ParcelFileDescriptor> parcelFd;
+
+    if (fd < 0) {
+        if (fd != -1) {
+            return STATUS_UNKNOWN_ERROR;
+        }
+        // parcelFd = nullptr
+    } else {  // fd >= 0
+        parcelFd = std::make_unique<ParcelFileDescriptor>(unique_fd(fd));
+    }
+
+    status_t status = parcel->get()->writeNullableParcelable(parcelFd);
+
+    // ownership is retained by caller
+    if (parcelFd != nullptr) {
+        (void)parcelFd->release().release();
+    }
+
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) {
+    std::unique_ptr<ParcelFileDescriptor> parcelFd;
+
+    status_t status = parcel->get()->readParcelable(&parcelFd);
+    if (status != STATUS_OK) return PruneStatusT(status);
+
+    if (parcelFd) {
+        *fd = parcelFd->release().release();
+    } else {
+        *fd = -1;
+    }
+
+    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) {
-    const uint8_t* str8 = (uint8_t*)string;
+binder_status_t AParcel_writeString(AParcel* parcel, const char* string, int32_t length) {
+    if (string == nullptr) {
+        if (length != -1) {
+            LOG(WARNING) << __func__ << ": null string must be used with length == -1.";
+            return STATUS_BAD_VALUE;
+        }
 
+        status_t err = parcel->get()->writeInt32(-1);
+        return PruneStatusT(err);
+    }
+
+    if (length < 0) {
+        LOG(WARNING) << __func__ << ": Negative string length: " << length;
+        return STATUS_BAD_VALUE;
+    }
+
+    const uint8_t* str8 = (uint8_t*)string;
     const ssize_t len16 = utf8_to_utf16_length(str8, length);
 
     if (len16 < 0 || len16 >= std::numeric_limits<int32_t>::max()) {
@@ -98,13 +329,16 @@
     return STATUS_OK;
 }
 
-binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_reallocator reallocator,
-                                   AParcel_string_getter 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);
 
     if (str16 == nullptr) {
-        LOG(WARNING) << __func__ << ": Failed to read string in place.";
+        if (allocator(stringData, -1, nullptr)) {
+            return STATUS_OK;
+        }
+
         return STATUS_UNEXPECTED_NULL;
     }
 
@@ -116,16 +350,16 @@
         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);
-    char* str8 = getter(*stringData);
+    char* str8;
+    bool success = allocator(stringData, len8, &str8);
 
-    if (str8 == nullptr) {
-        LOG(WARNING) << __func__ << ": AParcel_string_allocator failed to allocate.";
+    if (!success || str8 == nullptr) {
+        LOG(WARNING) << __func__ << ": AParcel_stringAllocator failed to allocate.";
         return STATUS_NO_MEMORY;
     }
 
@@ -134,6 +368,110 @@
     return STATUS_OK;
 }
 
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                         AParcel_stringArrayElementGetter getter) {
+    // we have no clue if arrayData represents a null object or not, we can only infer from length
+    bool arrayIsNull = length < 0;
+    binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length);
+    if (status != STATUS_OK) return status;
+    if (length <= 0) return STATUS_OK;
+
+    for (int32_t i = 0; i < length; i++) {
+        int32_t elementLength = 0;
+        const char* str = getter(arrayData, i, &elementLength);
+        if (str == nullptr && elementLength != -1) return STATUS_BAD_VALUE;
+
+        binder_status_t status = AParcel_writeString(parcel, str, elementLength);
+        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
+    int32_t index;    // index into the string array
+    AParcel_stringArrayElementAllocator elementAllocator;
+
+    static bool Allocator(void* stringData, int32_t length, char** buffer) {
+        StringArrayElementAllocationAdapter* adapter =
+                static_cast<StringArrayElementAllocationAdapter*>(stringData);
+        return adapter->elementAllocator(adapter->arrayData, adapter->index, length, buffer);
+    }
+};
+
+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 < -1) return STATUS_BAD_VALUE;
+
+    if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+
+    if (length == -1) return STATUS_OK;  // null string array
+
+    StringArrayElementAllocationAdapter adapter{
+            .arrayData = arrayData,
+            .index = 0,
+            .elementAllocator = elementAllocator,
+    };
+
+    for (; adapter.index < length; adapter.index++) {
+        binder_status_t status = AParcel_readString(parcel, static_cast<void*>(&adapter),
+                                                    StringArrayElementAllocationAdapter::Allocator);
+
+        if (status != STATUS_OK) return status;
+    }
+
+    return STATUS_OK;
+}
+
+binder_status_t AParcel_writeParcelableArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                             AParcel_writeParcelableElement elementWriter) {
+    // we have no clue if arrayData represents a null object or not, we can only infer from length
+    bool arrayIsNull = length < 0;
+    binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length);
+    if (status != STATUS_OK) return status;
+    if (length <= 0) return STATUS_OK;
+
+    for (int32_t i = 0; i < length; i++) {
+        binder_status_t status = elementWriter(parcel, arrayData, i);
+        if (status != STATUS_OK) return status;
+    }
+
+    return STATUS_OK;
+}
+
+binder_status_t AParcel_readParcelableArray(const AParcel* parcel, void* arrayData,
+                                            AParcel_parcelableArrayAllocator allocator,
+                                            AParcel_readParcelableElement elementReader) {
+    const Parcel* rawParcel = parcel->get();
+
+    int32_t length;
+    status_t status = rawParcel->readInt32(&length);
+
+    if (status != STATUS_OK) return PruneStatusT(status);
+    if (length < -1) return STATUS_BAD_VALUE;
+
+    if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+
+    if (length == -1) return STATUS_OK;  // null array
+
+    for (int32_t i = 0; i < length; i++) {
+        binder_status_t status = elementReader(parcel, arrayData, i);
+        if (status != STATUS_OK) return status;
+    }
+
+    return STATUS_OK;
+}
+
 // See gen_parcel_helper.py. These auto-generated read/write methods use the same types for
 // libbinder and this library.
 // @START
@@ -227,4 +565,89 @@
     return PruneStatusT(status);
 }
 
+binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, int32_t length) {
+    return WriteArray<int32_t>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData,
+                                         int32_t length) {
+    return WriteArray<uint32_t>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, int32_t length) {
+    return WriteArray<int64_t>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData,
+                                         int32_t length) {
+    return WriteArray<uint64_t>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, int32_t length) {
+    return WriteArray<float>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, int32_t length) {
+    return WriteArray<double>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                       AParcel_boolArrayGetter getter) {
+    return WriteArray<bool>(parcel, arrayData, length, getter, &Parcel::writeBool);
+}
+
+binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, int32_t length) {
+    return WriteArray<char16_t>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, int32_t length) {
+    return WriteArray<int8_t>(parcel, arrayData, length);
+}
+
+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_uint32ArrayAllocator allocator) {
+    return ReadArray<uint32_t>(parcel, arrayData, allocator);
+}
+
+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_uint64ArrayAllocator allocator) {
+    return ReadArray<uint64_t>(parcel, arrayData, allocator);
+}
+
+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_doubleArrayAllocator allocator) {
+    return ReadArray<double>(parcel, arrayData, allocator);
+}
+
+binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_boolArrayAllocator allocator,
+                                      AParcel_boolArraySetter setter) {
+    return ReadArray<bool>(parcel, arrayData, allocator, setter, &Parcel::readBool);
+}
+
+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_byteArrayAllocator allocator) {
+    return ReadArray<int8_t>(parcel, arrayData, allocator);
+}
+
 // @END
diff --git a/libs/binder/ndk/parcel_internal.h b/libs/binder/ndk/parcel_internal.h
index d69971f..f292309 100644
--- a/libs/binder/ndk/parcel_internal.h
+++ b/libs/binder/ndk/parcel_internal.h
@@ -29,7 +29,7 @@
 
     AParcel(const AIBinder* binder) : AParcel(binder, new ::android::Parcel, true /*owns*/) {}
     AParcel(const AIBinder* binder, ::android::Parcel* parcel, bool owns)
-          : mBinder(binder), mParcel(parcel), mOwns(owns) {}
+        : mBinder(binder), mParcel(parcel), mOwns(owns) {}
 
     ~AParcel() {
         if (mOwns) {
@@ -43,7 +43,7 @@
 
     const AIBinder* getBinder() { return mBinder; }
 
-private:
+   private:
     // This object is associated with a calls to a specific AIBinder object. This is used for sanity
     // checking to make sure that a parcel is one that is expected.
     const AIBinder* mBinder;
diff --git a/libs/binder/ndk/runtests.sh b/libs/binder/ndk/runtests.sh
index 2257eb2..a0c49fb 100755
--- a/libs/binder/ndk/runtests.sh
+++ b/libs/binder/ndk/runtests.sh
@@ -22,12 +22,13 @@
 set -ex
 
 function run_libbinder_ndk_test() {
-	adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
-	local pid=$!
-	trap "kill $pid" ERR
-	adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client
-	trap '' ERR
-	kill $pid
+    adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
+
+    # avoid getService 1s delay for most runs, non-critical
+    sleep 0.1
+
+    adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client; \
+        adb shell killall libbinder_ndk_test_server
 }
 
 [ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \
@@ -40,4 +41,5 @@
 # very simple unit tests, tests things outside of the NDK as well
 run_libbinder_ndk_test
 
-atest android.binder.cts.NdkBinderTest
+# CTS tests (much more comprehensive, new tests should ideally go here)
+atest android.binder.cts
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
index bbd3e5d..8f587d2 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -30,13 +30,15 @@
     ("Byte", "int8_t"),
 ]
 
-def replaceFileTags(path, content):
+non_contiguously_addressable = {"Bool"}
+
+def replaceFileTags(path, content, start_tag, end_tag):
     print("Updating", path)
     with open(path, "r+") as f:
         lines = f.readlines()
 
-        start = lines.index("// @START\n")
-        end = lines.index("// @END\n")
+        start = lines.index("// @" + start_tag + "\n")
+        end = lines.index("// @" + end_tag + "\n")
 
         if end <= start or start < 0 or end < 0:
             print("Failed to find tags in", path)
@@ -59,12 +61,19 @@
 
     print("Updating auto-generated code")
 
+    pre_header = ""
     header = ""
     source = ""
+    cpp_helper = ""
 
     for pretty, cpp in data_types:
         header += "/**\n"
         header += " * Writes " + cpp + " value to the next location in a non-null parcel.\n"
+        header += " *\n"
+        header += " * \\param parcel the parcel to write to.\n"
+        header += " * \\param value the value to write to the parcel.\n"
+        header += " *\n"
+        header += " * \\return STATUS_OK on successful write.\n"
         header += " */\n"
         header += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) __INTRODUCED_IN(29);\n\n"
         source += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) {\n"
@@ -75,6 +84,11 @@
     for pretty, cpp in data_types:
         header += "/**\n"
         header += " * Reads into " + cpp + " value from the next location in a non-null parcel.\n"
+        header += " *\n"
+        header += " * \\param parcel the parcel to read from.\n"
+        header += " * \\param value the value to read from the parcel.\n"
+        header += " *\n"
+        header += " * \\return STATUS_OK on successful read.\n"
         header += " */\n"
         header += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) __INTRODUCED_IN(29);\n\n"
         source += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) {\n"
@@ -82,8 +96,189 @@
         source += "    return PruneStatusT(status);\n"
         source += "}\n\n"
 
-    replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header)
-    replaceFileTags(ROOT + "parcel.cpp", source)
+    for pretty, cpp in data_types:
+        nca = pretty in non_contiguously_addressable
+
+        arg_types = "const " + cpp + "* arrayData, int32_t length"
+        if nca: arg_types = "const void* arrayData, int32_t length, AParcel_" + pretty.lower() + "ArrayGetter getter"
+        args = "arrayData, length"
+        if nca: args = "arrayData, length, getter, &Parcel::write" + pretty
+
+        header += "/**\n"
+        header += " * Writes an array of " + cpp + " to the next location in a non-null parcel.\n"
+        if nca:
+            header += " *\n"
+            header += " * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying values to write "
+            header += "to the parcel.\n"
+        header += " *\n"
+        header += " * \\param parcel the parcel to write to.\n"
+        if nca:
+            header += " * \\param arrayData some external representation of an array.\n"
+            header += " * \\param length the length of arrayData (or -1 if this represents a null array).\n"
+            header += " * \\param getter the callback to retrieve data at specific locations in the array.\n"
+        else:
+            header += " * \\param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).\n"
+            header += " * \\param length the length of arrayData or -1 if this represents a null array.\n"
+        header += " *\n"
+        header += " * \\return STATUS_OK on successful write.\n"
+        header += " */\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
+
+        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"
+
+        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. If length is -1, then this should allocate some representation of a null array.\n"
+            pre_header += " *\n"
+            pre_header += " * See also " + read_func + "\n"
+            pre_header += " *\n"
+            pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+            pre_header += " * \\param length the length to allocate arrayData to (or -1 if this represents a null array).\n"
+            pre_header += " *\n"
+            pre_header += " * \\return whether the allocation succeeded.\n"
+            pre_header += " */\n"
+            pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, int32_t length);\n\n"
+
+            pre_header += "/**\n"
+            pre_header += " * This is called to get the underlying data from an arrayData object at index.\n"
+            pre_header += " *\n"
+            pre_header += " * See also " + write_func + "\n"
+            pre_header += " *\n"
+            pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+            pre_header += " * \\param index the index of the value to be retrieved.\n"
+            pre_header += " *\n"
+            pre_header += " * \\return the value of the array at index index.\n"
+            pre_header += " */\n"
+            pre_header += "typedef " + cpp + " (*" + getter_type + ")(const void* arrayData, size_t index);\n\n"
+
+            pre_header += "/**\n"
+            pre_header += " * This is called to set an underlying value in an arrayData object at index.\n"
+            pre_header += " *\n"
+            pre_header += " * See also " + read_func + "\n"
+            pre_header += " *\n"
+            pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+            pre_header += " * \\param index the index of the value to be set.\n"
+            pre_header += " * \\param value the value to set at index index.\n"
+            pre_header += " */\n"
+            pre_header += "typedef void (*" + setter_type + ")(void* arrayData, size_t index, " + cpp + " value);\n\n"
+        else:
+            pre_header += "/**\n"
+            pre_header += " * This is called to get the underlying data from an arrayData object.\n"
+            pre_header += " *\n"
+            pre_header += " * The implementation of this function should allocate a contiguous array of size 'length' and "
+            pre_header += "return that underlying buffer to be filled out. If there is an error or length is 0, null may be "
+            pre_header += "returned. If length is -1, this should allocate some representation of a null array.\n"
+            pre_header += " *\n"
+            pre_header += " * See also " + read_func + "\n"
+            pre_header += " *\n"
+            pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+            pre_header += " * \\param length the length to allocate arrayData to.\n"
+            pre_header += " * \\param outBuffer a buffer of " + cpp + " of size 'length' (if length is >= 0, if length is 0, "
+            pre_header += "this may be nullptr).\n"
+            pre_header += " *\n"
+            pre_header += " * \\return whether or not the allocation was successful (or whether a null array is represented when length is -1).\n"
+            pre_header += " */\n"
+            pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, int32_t length, " + cpp + "** outBuffer);\n\n"
+
+        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")]
+
+        read_type_args = ", ".join((varType + " " + name for varType, name in read_array_args))
+        read_call_args = ", ".join((name for varType, name in read_array_args))
+
+        header += "/**\n"
+        header += " * Reads an array of " + cpp + " from the next location in a non-null parcel.\n"
+        header += " *\n"
+        if nca:
+            header += " * First, allocator will be called with the length of the array. Then, for every i in [0, length), "
+            header += "setter(arrayData, i, x) will be called where x is the value at the associated index.\n"
+        else:
+            header += " * First, allocator will be called with the length of the array. If the allocation succeeds and the "
+            header += "length is greater than zero, the buffer returned by the allocator will be filled with the corresponding data\n"
+        header += " *\n"
+        header += " * \\param parcel the parcel to read from.\n"
+        header += " * \\param arrayData some external representation of an array.\n"
+        header += " * \\param allocator the callback that will be called to allocate the array.\n"
+        if nca:
+            header += " * \\param setter the callback that will be called to set a value at a specific location in the array.\n"
+        header += " *\n"
+        header += " * \\return STATUS_OK on successful read.\n"
+        header += " */\n"
+        header += "binder_status_t " + 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 + ">(" + 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(), vec.size()"
+        if nca: write_args = "static_cast<const void*>(&vec), vec.size(), AParcel_stdVectorGetter<" + cpp + ">"
+        cpp_helper += "    return AParcel_write" + pretty + "Array(parcel, " + write_args + ");\n"
+        cpp_helper += "}\n\n"
+
+        cpp_helper += "/**\n"
+        cpp_helper += " * Writes an optional 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::optional<std::vector<" + cpp + ">>& vec) {\n"
+        extra_args = ""
+        if nca: extra_args = ", AParcel_stdVectorGetter<" + cpp + ">"
+        cpp_helper += "    if (!vec) return AParcel_write" + pretty + "Array(parcel, nullptr, -1" + extra_args + ");\n"
+        cpp_helper += "    return AParcel_writeVector(parcel, *vec);\n"
+        cpp_helper += "}\n\n"
+
+        cpp_helper += "/**\n"
+        cpp_helper += " * Reads a vector of " + cpp + " from the next location in a non-null parcel.\n"
+        cpp_helper += " */\n"
+        cpp_helper += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n"
+        cpp_helper += "    void* vectorData = static_cast<void*>(vec);\n"
+        read_args = []
+        read_args += ["parcel"]
+        read_args += ["vectorData"]
+        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"
+
+        cpp_helper += "/**\n"
+        cpp_helper += " * Reads an optional vector of " + cpp + " from the next location in a non-null parcel.\n"
+        cpp_helper += " */\n"
+        cpp_helper += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::optional<std::vector<" + cpp + ">>* vec) {\n"
+        cpp_helper += "    void* vectorData = static_cast<void*>(vec);\n"
+        read_args = []
+        read_args += ["parcel"]
+        read_args += ["vectorData"]
+        if nca:
+            read_args += ["AParcel_nullableStdVectorExternalAllocator<bool>"]
+            read_args += ["AParcel_nullableStdVectorSetter<" + cpp + ">"]
+        else:
+            read_args += ["AParcel_nullableStdVectorAllocator<" + cpp + ">"]
+        cpp_helper += "    return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n"
+        cpp_helper += "}\n\n"
+
+    replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", pre_header, "START-PRIMITIVE-VECTOR-GETTERS", "END-PRIMITIVE-VECTOR-GETTERS")
+    replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header, "START-PRIMITIVE-READ-WRITE", "END-PRIMITIVE-READ-WRITE")
+    replaceFileTags(ROOT + "parcel.cpp", source, "START", "END")
+    replaceFileTags(ROOT + "include_ndk/android/binder_parcel_utils.h", cpp_helper, "START", "END")
 
     print("Updating DONE.")
 
diff --git a/libs/binder/ndk/status_internal.h b/libs/binder/ndk/status_internal.h
index 8c32baf..d39f0d8 100644
--- a/libs/binder/ndk/status_internal.h
+++ b/libs/binder/ndk/status_internal.h
@@ -22,13 +22,13 @@
 #include <utils/Errors.h>
 
 struct AStatus {
-    AStatus() {} // ok
+    AStatus() {}  // ok
     AStatus(::android::binder::Status&& status) : mStatus(std::move(status)) {}
 
     ::android::binder::Status* get() { return &mStatus; }
     const ::android::binder::Status* get() const { return &mStatus; }
 
-private:
+   private:
     ::android::binder::Status mStatus;
 };
 
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 8e40a01..b29b6e7 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-// This test is a unit test of the low-level API that is presented here.
-// Actual users should use AIDL to generate these complicated stubs.
-
 cc_defaults {
     name: "test_libbinder_ndk_defaults",
     shared_libs: [
@@ -55,6 +52,9 @@
     ],
 }
 
+// This test is a unit test of the low-level API that is presented here,
+// specifically the parts which are outside of the NDK. Actual users should
+// also instead use AIDL to generate these stubs. See android.binder.cts.
 cc_test {
     name: "libbinder_ndk_test_client",
     defaults: ["test_libbinder_ndk_test_defaults"],
diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/test/iface.cpp
index 0dc3cc4..6ef964e 100644
--- a/libs/binder/ndk/test/iface.cpp
+++ b/libs/binder/ndk/test/iface.cpp
@@ -18,10 +18,13 @@
 #include <android/binder_manager.h>
 #include <iface/iface.h>
 
+#include <android/binder_auto_utils.h>
+
 using ::android::sp;
 using ::android::wp;
 
 const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo";
+const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die";
 const char* kIFooDescriptor = "my-special-IFoo-class";
 
 struct IFoo_Class_Data {
@@ -49,12 +52,18 @@
     switch (code) {
         case IFoo::DOFOO: {
             int32_t valueIn;
+            int32_t valueOut;
             stat = AParcel_readInt32(in, &valueIn);
             if (stat != STATUS_OK) break;
-            int32_t valueOut = foo->doubleNumber(valueIn);
+            stat = foo->doubleNumber(valueIn, &valueOut);
+            if (stat != STATUS_OK) break;
             stat = AParcel_writeInt32(out, valueOut);
             break;
         }
+        case IFoo::DIE: {
+            stat = foo->die();
+            break;
+        }
     }
 
     return stat;
@@ -64,29 +73,43 @@
                                                      IFoo_Class_onDestroy, IFoo_Class_onTransact);
 
 class BpFoo : public IFoo {
-public:
+   public:
     BpFoo(AIBinder* binder) : mBinder(binder) {}
     virtual ~BpFoo() { AIBinder_decStrong(mBinder); }
 
-    virtual int32_t doubleNumber(int32_t in) {
+    virtual binder_status_t doubleNumber(int32_t in, int32_t* out) {
+        binder_status_t stat = STATUS_OK;
+
         AParcel* parcelIn;
-        CHECK(STATUS_OK == AIBinder_prepareTransaction(mBinder, &parcelIn));
+        stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
+        if (stat != STATUS_OK) return stat;
 
-        CHECK(STATUS_OK == AParcel_writeInt32(parcelIn, in));
+        stat = AParcel_writeInt32(parcelIn, in);
+        if (stat != STATUS_OK) return stat;
 
-        AParcel* parcelOut;
-        CHECK(STATUS_OK ==
-              AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, &parcelOut, 0 /*flags*/));
+        ::ndk::ScopedAParcel parcelOut;
+        stat = AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, parcelOut.getR(), 0 /*flags*/);
+        if (stat != STATUS_OK) return stat;
 
-        int32_t out;
-        CHECK(STATUS_OK == AParcel_readInt32(parcelOut, &out));
+        stat = AParcel_readInt32(parcelOut.get(), out);
+        if (stat != STATUS_OK) return stat;
 
-        AParcel_delete(parcelOut);
-
-        return out;
+        return stat;
     }
 
-private:
+    virtual binder_status_t die() {
+        binder_status_t stat = STATUS_OK;
+
+        AParcel* parcelIn;
+        stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
+
+        ::ndk::ScopedAParcel parcelOut;
+        stat = AIBinder_transact(mBinder, IFoo::DIE, &parcelIn, parcelOut.getR(), 0 /*flags*/);
+
+        return stat;
+    }
+
+   private:
     // Always assumes one refcount
     AIBinder* mBinder;
 };
@@ -117,8 +140,8 @@
     return status;
 }
 
-sp<IFoo> IFoo::getService(const char* instance) {
-    AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr
+sp<IFoo> IFoo::getService(const char* instance, AIBinder** outBinder) {
+    AIBinder* binder = AServiceManager_getService(instance);  // maybe nullptr
     if (binder == nullptr) {
         return nullptr;
     }
@@ -128,14 +151,19 @@
         return nullptr;
     }
 
+    if (outBinder != nullptr) {
+        AIBinder_incStrong(binder);
+        *outBinder = binder;
+    }
+
     if (AIBinder_isRemote(binder)) {
-        sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder
+        sp<IFoo> ret = new BpFoo(binder);  // takes ownership of binder
         return ret;
     }
 
     IFoo_Class_Data* data = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder));
 
-    CHECK(data != nullptr); // always created with non-null data
+    CHECK(data != nullptr);  // always created with non-null data
 
     sp<IFoo> ret = data->foo;
 
@@ -143,7 +171,6 @@
     CHECK(held == binder);
     AIBinder_decStrong(held);
 
-    // IFoo only keeps a weak reference to AIBinder, so we can drop this
     AIBinder_decStrong(binder);
     return ret;
 }
diff --git a/libs/binder/ndk/test/include/iface/iface.h b/libs/binder/ndk/test/include/iface/iface.h
index 4c61e9d..cdf5493 100644
--- a/libs/binder/ndk/test/include/iface/iface.h
+++ b/libs/binder/ndk/test/include/iface/iface.h
@@ -19,22 +19,33 @@
 #include <android/binder_ibinder.h>
 #include <utils/RefBase.h>
 
+// warning: it is recommended to use AIDL output instead of this. binder_ibinder_utils.h and some of
+// the other niceties make sure that, for instance, binder proxies are always the same. They also
+// don't use internal Android APIs like refbase which are used here only for convenience.
+
 class IFoo : public virtual ::android::RefBase {
-public:
+   public:
     static const char* kSomeInstanceName;
+    static const char* kInstanceNameToDieFor;
+
     static AIBinder_Class* kClass;
 
     // Takes ownership of IFoo
     binder_status_t addService(const char* instance);
-    static ::android::sp<IFoo> getService(const char* instance);
+    static ::android::sp<IFoo> getService(const char* instance, AIBinder** outBinder = nullptr);
 
     enum Call {
         DOFOO = FIRST_CALL_TRANSACTION + 0,
+        DIE = FIRST_CALL_TRANSACTION + 1,
     };
 
     virtual ~IFoo();
-    virtual int32_t doubleNumber(int32_t in) = 0;
 
-private:
-    AIBinder_Weak* mWeakBinder = nullptr; // maybe owns AIBinder
+    virtual binder_status_t doubleNumber(int32_t in, int32_t* out) = 0;
+    virtual binder_status_t die() = 0;
+
+   private:
+    // this variable is only when IFoo is local (since this test combines 'IFoo' and 'BnFoo'), not
+    // for BpFoo.
+    AIBinder_Weak* mWeakBinder = nullptr;
 };
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index 22bf1e5..c159d71 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -21,6 +21,10 @@
 #include <gtest/gtest.h>
 #include <iface/iface.h>
 
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
 using ::android::sp;
 
 constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
@@ -34,7 +38,47 @@
 TEST(NdkBinder, DoubleNumber) {
     sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
     ASSERT_NE(foo, nullptr);
-    EXPECT_EQ(2, foo->doubleNumber(1));
+
+    int32_t out;
+    EXPECT_EQ(STATUS_OK, foo->doubleNumber(1, &out));
+    EXPECT_EQ(2, out);
+}
+
+void LambdaOnDeath(void* cookie) {
+    auto onDeath = static_cast<std::function<void(void)>*>(cookie);
+    (*onDeath)();
+};
+TEST(NdkBinder, DeathRecipient) {
+    using namespace std::chrono_literals;
+
+    AIBinder* binder;
+    sp<IFoo> foo = IFoo::getService(IFoo::kInstanceNameToDieFor, &binder);
+    ASSERT_NE(nullptr, foo.get());
+    ASSERT_NE(nullptr, binder);
+
+    std::mutex deathMutex;
+    std::condition_variable deathCv;
+    bool deathRecieved = false;
+
+    std::function<void(void)> onDeath = [&] {
+        std::cerr << "Binder died (as requested)." << std::endl;
+        deathRecieved = true;
+        deathCv.notify_one();
+    };
+
+    AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath);
+
+    EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath)));
+
+    // the binder driver should return this if the service dies during the transaction
+    EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
+
+    std::unique_lock<std::mutex> lock(deathMutex);
+    EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; }));
+    EXPECT_TRUE(deathRecieved);
+
+    AIBinder_DeathRecipient_delete(recipient);
+    AIBinder_decStrong(binder);
 }
 
 TEST(NdkBinder, RetrieveNonNdkService) {
@@ -52,9 +96,6 @@
 }
 
 TEST(NdkBinder, LinkToDeath) {
-    ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications
-    ABinderProcess_startThreadPool();
-
     AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
     ASSERT_NE(nullptr, binder);
 
@@ -72,9 +113,14 @@
 }
 
 class MyTestFoo : public IFoo {
-    int32_t doubleNumber(int32_t in) override {
-        LOG(INFO) << "doubleNumber " << in;
-        return 2 * in;
+    binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+        *out = 2 * in;
+        LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+        return STATUS_OK;
+    }
+    binder_status_t die() override {
+        ADD_FAILURE() << "die called on local instance";
+        return STATUS_OK;
     }
 };
 
@@ -87,7 +133,9 @@
     sp<IFoo> getFoo = IFoo::getService(kInstanceName);
     EXPECT_EQ(foo.get(), getFoo.get());
 
-    EXPECT_EQ(2, getFoo->doubleNumber(1));
+    int32_t out;
+    EXPECT_EQ(STATUS_OK, getFoo->doubleNumber(1, &out));
+    EXPECT_EQ(2, out);
 }
 
 TEST(NdkBinder, EqualityOfRemoteBinderPointer) {
@@ -132,5 +180,15 @@
     EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
 }
 
+int main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    ABinderProcess_setThreadPoolMaxThreadCount(1);  // to recieve death notifications/callbacks
+    ABinderProcess_startThreadPool();
+
+    return RUN_ALL_TESTS();
+}
+
 #include <android/binder_auto_utils.h>
 #include <android/binder_interface_utils.h>
+#include <android/binder_parcel_utils.h>
diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp
index 0718a69..a6e17e8 100644
--- a/libs/binder/ndk/test/main_server.cpp
+++ b/libs/binder/ndk/test/main_server.cpp
@@ -21,23 +21,37 @@
 using ::android::sp;
 
 class MyFoo : public IFoo {
-    int32_t doubleNumber(int32_t in) override {
-        LOG(INFO) << "doubling " << in;
-        return 2 * in;
+    binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+        *out = 2 * in;
+        LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+        return STATUS_OK;
+    }
+
+    binder_status_t die() override {
+        LOG(FATAL) << "IFoo::die called!";
+        return STATUS_UNKNOWN_ERROR;
     }
 };
 
-int main() {
+int service(const char* instance) {
     ABinderProcess_setThreadPoolMaxThreadCount(0);
 
     // Strong reference to MyFoo kept by service manager.
-    binder_status_t status = (new MyFoo)->addService(IFoo::kSomeInstanceName);
+    binder_status_t status = (new MyFoo)->addService(instance);
 
     if (status != STATUS_OK) {
-        LOG(FATAL) << "Could not register: " << status;
+        LOG(FATAL) << "Could not register: " << status << " " << instance;
     }
 
     ABinderProcess_joinThreadPool();
 
-    return 1;
+    return 1;  // should not return
+}
+
+int main() {
+    if (fork() == 0) {
+        return service(IFoo::kInstanceNameToDieFor);
+    }
+
+    return service(IFoo::kSomeInstanceName);
 }
diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh
index 49b4730..9a4577f 100755
--- a/libs/binder/ndk/update.sh
+++ b/libs/binder/ndk/update.sh
@@ -18,6 +18,6 @@
 set -ex
 
 # This script makes sure that the source code is in sync with the various scripts
-./scripts/init_map.sh > libbinder_ndk.map.txt
 ./scripts/gen_parcel_helper.py
 ./scripts/format.sh
+./scripts/init_map.sh > libbinder_ndk.map.txt
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 73c2eba..2dd86ba 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1295,7 +1295,7 @@
         }
         IPCThreadState::self()->flushCommands(); // flush BC_ENTER_LOOPER
 
-        epoll_fd = epoll_create1(0);
+        epoll_fd = epoll_create1(EPOLL_CLOEXEC);
         if (epoll_fd == -1) {
             return 1;
         }
diff --git a/libs/binder/tests/binderValueTypeTest.cpp b/libs/binder/tests/binderValueTypeTest.cpp
index c8f4697..f8922b0 100644
--- a/libs/binder/tests/binderValueTypeTest.cpp
+++ b/libs/binder/tests/binderValueTypeTest.cpp
@@ -22,7 +22,6 @@
 #include <vector>
 
 #include "android-base/file.h"
-#include "android-base/test_utils.h"
 #include <gtest/gtest.h>
 
 #include <binder/Parcel.h>
@@ -76,13 +75,13 @@
 
 VALUE_TYPE_TEST(bool, Boolean, true)
 VALUE_TYPE_TEST(int32_t, Int, 31337)
-VALUE_TYPE_TEST(int64_t, Long, 13370133701337l)
+VALUE_TYPE_TEST(int64_t, Long, 13370133701337L)
 VALUE_TYPE_TEST(double, Double, 3.14159265358979323846)
 VALUE_TYPE_TEST(String16, String, String16("Lovely"))
 
 VALUE_TYPE_VECTOR_TEST(bool, Boolean, true)
 VALUE_TYPE_VECTOR_TEST(int32_t, Int, 31337)
-VALUE_TYPE_VECTOR_TEST(int64_t, Long, 13370133701337l)
+VALUE_TYPE_VECTOR_TEST(int64_t, Long, 13370133701337L)
 VALUE_TYPE_VECTOR_TEST(double, Double, 3.14159265358979323846)
 VALUE_TYPE_VECTOR_TEST(String16, String, String16("Lovely"))
 
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 8b2f842..35296a9 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -47,6 +47,7 @@
         "android.hardware.camera.provider@2.4::ICameraProvider",
         "android.hardware.drm@1.0::IDrmFactory",
         "android.hardware.graphics.composer@2.1::IComposer",
+        "android.hardware.health@2.0::IHealth",
         "android.hardware.media.omx@1.0::IOmx",
         "android.hardware.media.omx@1.0::IOmxStore",
         "android.hardware.sensors@1.0::ISensors",
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index c8021e4..c96a2dd 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -381,7 +381,6 @@
 
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
-        mCore->waitWhileAllocatingLocked();
 
         if (format == 0) {
             format = mCore->mDefaultBufferFormat;
@@ -1345,7 +1344,9 @@
                 return;
             }
 
-            newBufferCount = mCore->mFreeSlots.size();
+            // Only allocate one buffer at a time to reduce risks of overlapping an allocation from
+            // both allocateBuffers and dequeueBuffer.
+            newBufferCount = mCore->mFreeSlots.empty() ? 0 : 1;
             if (newBufferCount == 0) {
                 return;
             }
@@ -1360,7 +1361,7 @@
         } // Autolock scope
 
         Vector<sp<GraphicBuffer>> buffers;
-        for (size_t i = 0; i <  newBufferCount; ++i) {
+        for (size_t i = 0; i < newBufferCount; ++i) {
             sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
                     allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
                     allocUsage, allocName);
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 0749fde..0b37960 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -355,7 +355,7 @@
         data.writeUint32(height);
         data.writeInt32(static_cast<int32_t>(format));
         data.writeUint64(usage);
-        status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply);
+        status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply, TF_ONE_WAY);
         if (result != NO_ERROR) {
             ALOGE("allocateBuffers failed to transact: %d", result);
         }
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index e22bc70..d2d27e8 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -332,6 +332,34 @@
         return result;
     }
 
+    virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
+        Parcel data, reply;
+        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("getDisplayViewport failed to writeInterfaceToken: %d", result);
+            return result;
+        }
+        result = data.writeStrongBinder(display);
+        if (result != NO_ERROR) {
+            ALOGE("getDisplayViewport failed to writeStrongBinder: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_VIEWPORT, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getDisplayViewport failed to transact: %d", result);
+            return result;
+        }
+        result = reply.readInt32();
+        if (result == NO_ERROR) {
+            result = reply.read(*outViewport);
+            if (result != NO_ERROR) {
+                ALOGE("getDisplayViewport failed to read: %d", result);
+                return result;
+            }
+        }
+        return result;
+    }
+
     virtual int getActiveConfig(const sp<IBinder>& display)
     {
         Parcel data, reply;
@@ -724,6 +752,26 @@
             }
             return NO_ERROR;
         }
+        case GET_DISPLAY_VIEWPORT: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            Rect outViewport;
+            sp<IBinder> display = nullptr;
+            status_t result = data.readStrongBinder(&display);
+            if (result != NO_ERROR) {
+                ALOGE("getDisplayViewport failed to readStrongBinder: %d", result);
+                return result;
+            }
+            result = getDisplayViewport(display, &outViewport);
+            result = reply->writeInt32(result);
+            if (result == NO_ERROR) {
+                result = reply->write(outViewport);
+                if (result != NO_ERROR) {
+                    ALOGE("getDisplayViewport failed to write: %d", result);
+                    return result;
+                }
+            }
+            return NO_ERROR;
+        }
         case GET_ACTIVE_CONFIG: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> display = data.readStrongBinder();
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 339bd0f..2de14c8 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -464,8 +464,12 @@
     if (interval > maxSwapInterval)
         interval = maxSwapInterval;
 
+    const bool wasSwapIntervalZero = mSwapIntervalZero;
     mSwapIntervalZero = (interval == 0);
-    mGraphicBufferProducer->setAsyncMode(mSwapIntervalZero);
+
+    if (mSwapIntervalZero != wasSwapIntervalZero) {
+        mGraphicBufferProducer->setAsyncMode(mSwapIntervalZero);
+    }
 
     return NO_ERROR;
 }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 63560c4..f3c6fd2 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -718,6 +718,10 @@
     return NO_ERROR;
 }
 
+status_t SurfaceComposerClient::getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
+    return ComposerService::getComposerService()->getDisplayViewport(display, outViewport);
+}
+
 int SurfaceComposerClient::getActiveConfig(const sp<IBinder>& display) {
     return ComposerService::getComposerService()->getActiveConfig(display);
 }
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
index 3b89291..b1e44bb 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -896,7 +896,7 @@
     int const* constFds = static_cast<int const*>(baseFds.get());
     numFds = baseNumFds;
     if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
-        for (auto nhA : nhAA) {
+        for (const auto& nhA : nhAA) {
             for (auto nh : nhA) {
                 if (nh != nullptr) {
                     native_handle_close(nh);
@@ -907,8 +907,8 @@
         return false;
     }
 
-    for (auto nhA : nhAA) {
-        for (auto nh : nhA) {
+    for (const auto& nhA : nhAA) {
+        for (const auto& nh : nhA) {
             if (nh != nullptr) {
                 native_handle_delete(nh);
             }
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e401572..99a3a75 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -157,6 +157,9 @@
     virtual status_t getDisplayStats(const sp<IBinder>& display,
             DisplayStatInfo* stats) = 0;
 
+    /* returns display viewport information of the given display */
+    virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) = 0;
+
     /* indicates which of the configurations returned by getDisplayInfo is
      * currently active */
     virtual int getActiveConfig(const sp<IBinder>& display) = 0;
@@ -250,7 +253,8 @@
         ENABLE_VSYNC_INJECTIONS,
         INJECT_VSYNC,
         GET_LAYER_DEBUG_INFO,
-        CREATE_SCOPED_CONNECTION
+        CREATE_SCOPED_CONNECTION,
+        GET_DISPLAY_VIEWPORT
     };
 
     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 377fe68..ad8a8b0 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -79,6 +79,9 @@
     static status_t getDisplayInfo(const sp<IBinder>& display,
             DisplayInfo* info);
 
+    // Get the display viewport for the given display
+    static status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport);
+
     // Get the index of the current active configuration (relative to the list
     // returned by getDisplayInfo)
     static int getActiveConfig(const sp<IBinder>& display);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 2c02ba6..6e196bf 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -581,6 +581,9 @@
             Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
     status_t getDisplayStats(const sp<IBinder>& /*display*/,
             DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
+    status_t getDisplayViewport(const sp<IBinder>& /*display*/, Rect* /*outViewport*/) override {
+        return NO_ERROR;
+    }
     int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
     status_t setActiveConfig(const sp<IBinder>& /*display*/, int /*id*/)
             override {
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index a2d6a8a..2f39976 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -16,7 +16,6 @@
 
 cc_library {
     name: "libinput",
-    cpp_std: "c++17",
     host_supported: true,
     cflags: [
         "-Wall",
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index f72e49b..f834c55 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -327,8 +327,8 @@
         eventTime = event->getHistoricalEventTime(h);
         for (size_t i = 0; i < pointerCount; i++) {
             uint32_t index = pointerIndex[i];
-            positions[index].x = event->getHistoricalRawX(i, h);
-            positions[index].y = event->getHistoricalRawY(i, h);
+            positions[index].x = event->getHistoricalX(i, h);
+            positions[index].y = event->getHistoricalY(i, h);
         }
         addMovement(eventTime, idBits, positions);
     }
@@ -336,8 +336,8 @@
     eventTime = event->getEventTime();
     for (size_t i = 0; i < pointerCount; i++) {
         uint32_t index = pointerIndex[i];
-        positions[index].x = event->getRawX(i);
-        positions[index].y = event->getRawY(i);
+        positions[index].x = event->getX(i);
+        positions[index].y = event->getY(i);
     }
     addMovement(eventTime, idBits, positions);
 }
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 5fbb3b2..d74bdb3 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -43,10 +43,6 @@
         "-Wno-unused-function",
     ],
 
-    cppflags: [
-        "-std=c++1z"
-    ],
-
     version_script: "libnativewindow.map.txt",
 
     srcs: [
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 9ca4941..52b4582 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -15,12 +15,31 @@
  */
 
 /**
- * @addtogroup NativeActivity Native Activity
- * @{
- */
-
-/**
  * @file hardware_buffer.h
+ * @brief API for native hardware buffers.
+ */
+/**
+ * @defgroup AHardwareBuffer Native Hardware Buffer
+ *
+ * AHardwareBuffer objects represent chunks of memory that can be
+ * accessed by various hardware components in the system. It can be
+ * easily converted to the Java counterpart
+ * android.hardware.HardwareBuffer and passed between processes using
+ * Binder. All operations involving AHardwareBuffer and HardwareBuffer
+ * are zero-copy, i.e., passing AHardwareBuffer to another process
+ * creates a shared view of the same region of memory.
+ *
+ * AHardwareBuffers can be bound to EGL/OpenGL and Vulkan primitives.
+ * For EGL, use the extension function eglGetNativeClientBufferANDROID
+ * to obtain an EGLClientBuffer and pass it directly to
+ * eglCreateImageKHR. Refer to the EGL extensions
+ * EGL_ANDROID_get_native_client_buffer and
+ * EGL_ANDROID_image_native_buffer for more information. In Vulkan,
+ * the contents of the AHardwareBuffer can be accessed as external
+ * memory. See the VK_ANDROID_external_memory_android_hardware_buffer
+ * extension for details.
+ *
+ * @{
  */
 
 #ifndef ANDROID_HARDWARE_BUFFER_H
@@ -37,7 +56,7 @@
 /**
  * Buffer pixel formats.
  */
-enum {
+enum AHardwareBuffer_Format {
     /**
      * Corresponding formats:
      *   Vulkan: VK_FORMAT_R8G8B8A8_UNORM
@@ -83,8 +102,10 @@
     AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM        = 0x2b,
 
     /**
-     * An opaque binary blob format that must have height 1, with width equal to
-     * the buffer size in bytes.
+     * Opaque binary blob format.
+     * Must have height 1 and one layer, with width equal to the buffer
+     * size in bytes. Corresponds to Vulkan buffers and OpenGL buffer
+     * objects. Can be bound to the latter using GL_EXT_external_buffer.
      */
     AHARDWAREBUFFER_FORMAT_BLOB                     = 0x21,
 
@@ -134,21 +155,39 @@
 /**
  * Buffer usage flags, specifying how the buffer will be accessed.
  */
-enum {
-    /// The buffer will never be read by the CPU.
+enum AHardwareBuffer_UsageFlags {
+    /// The buffer will never be locked for direct CPU reads using the
+    /// AHardwareBuffer_lock() function. Note that reading the buffer
+    /// using OpenGL or Vulkan functions or memory mappings is still
+    /// allowed.
     AHARDWAREBUFFER_USAGE_CPU_READ_NEVER        = 0UL,
-    /// The buffer will sometimes be read by the CPU.
+    /// The buffer will sometimes be locked for direct CPU reads using
+    /// the AHardwareBuffer_lock() function. Note that reading the
+    /// buffer using OpenGL or Vulkan functions or memory mappings
+    /// does not require the presence of this flag.
     AHARDWAREBUFFER_USAGE_CPU_READ_RARELY       = 2UL,
-    /// The buffer will often be read by the CPU.
+    /// The buffer will often be locked for direct CPU reads using
+    /// the AHardwareBuffer_lock() function. Note that reading the
+    /// buffer using OpenGL or Vulkan functions or memory mappings
+    /// does not require the presence of this flag.
     AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN        = 3UL,
     /// CPU read value mask.
     AHARDWAREBUFFER_USAGE_CPU_READ_MASK         = 0xFUL,
 
-    /// The buffer will never be written by the CPU.
+    /// The buffer will never be locked for direct CPU writes using the
+    /// AHardwareBuffer_lock() function. Note that writing the buffer
+    /// using OpenGL or Vulkan functions or memory mappings is still
+    /// allowed.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER       = 0UL << 4,
-    /// The buffer will sometimes be written to by the CPU.
+    /// The buffer will sometimes be locked for direct CPU writes using
+    /// the AHardwareBuffer_lock() function. Note that writing the
+    /// buffer using OpenGL or Vulkan functions or memory mappings
+    /// does not require the presence of this flag.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY      = 2UL << 4,
-    /// The buffer will often be written to by the CPU.
+    /// The buffer will often be locked for direct CPU writes using
+    /// the AHardwareBuffer_lock() function. Note that writing the
+    /// buffer using OpenGL or Vulkan functions or memory mappings
+    /// does not require the presence of this flag.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN       = 3UL << 4,
     /// CPU write value mask.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK        = 0xFUL << 4,
@@ -156,24 +195,51 @@
     /// The buffer will be read from by the GPU as a texture.
     AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE      = 1UL << 8,
     /**
-     * The buffer will be written to by the GPU as a framebuffer attachment.
-     * Note that the name of this flag is somewhat misleading: it does not imply
-     * that the buffer contains a color format. A buffer with depth or stencil
-     * format that will be used as a framebuffer attachment should also have
-     * this flag.
+     * The buffer will be written to by the GPU as a framebuffer
+     * attachment.
+     *
+     * Note that the name of this flag is somewhat misleading: it does
+     * not imply that the buffer contains a color format. A buffer with
+     * depth or stencil format that will be used as a framebuffer
+     * attachment should also have this flag.
      */
     AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT       = 1UL << 9,
-    /// The buffer must not be used outside of a protected hardware path.
+    /**
+     * The buffer is protected from direct CPU access or being read by
+     * non-secure hardware, such as video encoders.
+     *
+     * This flag is incompatible with CPU read and write flags. It is
+     * mainly used when handling DRM video. Refer to the EGL extension
+     * EGL_EXT_protected_content and GL extension
+     * GL_EXT_protected_textures for more information on how these
+     * buffers are expected to behave.
+     */
     AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT      = 1UL << 14,
     /// The buffer will be read by a hardware video encoder.
     AHARDWAREBUFFER_USAGE_VIDEO_ENCODE           = 1UL << 16,
-    /// The buffer will be used for direct writes from sensors.
+    /**
+     * The buffer will be used for direct writes from sensors.
+     * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
+     */
     AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA     = 1UL << 23,
-    /// The buffer will be used as a shader storage or uniform buffer object.
+    /**
+     * The buffer will be used as a shader storage or uniform buffer object.
+     * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
+     */
     AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER        = 1UL << 24,
-    /// The buffer will be used as a cube map texture.
+    /**
+     * The buffer will be used as a cube map texture.
+     * When this flag is present, the buffer must have a layer count
+     * that is a multiple of 6. Note that buffers with this flag must be
+     * bound to OpenGL textures using the extension
+     * GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image.
+     */
     AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP               = 1UL << 25,
-    /// The buffer contains a complete mipmap hierarchy.
+    /**
+     * The buffer contains a complete mipmap hierarchy.
+     * Note that buffers with this flag must be bound to OpenGL textures using
+     * the extension GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image.
+     */
     AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE        = 1UL << 26,
 
     AHARDWAREBUFFER_USAGE_VENDOR_0  = 1ULL << 28,
@@ -199,27 +265,42 @@
 };
 
 /**
- * Buffer description. Used for allocating new buffers and querying parameters
- * of existing ones.
+ * Buffer description. Used for allocating new buffers and querying
+ * parameters of existing ones.
  */
 typedef struct AHardwareBuffer_Desc {
     uint32_t    width;      ///< Width in pixels.
     uint32_t    height;     ///< Height in pixels.
-    uint32_t    layers;     ///< Number of images in an image array.
-    uint32_t    format;     ///< One of AHARDWAREBUFFER_FORMAT_*
-    uint64_t    usage;      ///< Combination of AHARDWAREBUFFER_USAGE_*
+    /**
+     * Number of images in an image array. AHardwareBuffers with one
+     * layer correspond to regular 2D textures. AHardwareBuffers with
+     * more than layer correspond to texture arrays. If the layer count
+     * is a multiple of 6 and the usage flag
+     * AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP is present, the buffer is
+     * a cube map or a cube map array.
+     */
+    uint32_t    layers;
+    uint32_t    format;     ///< One of AHardwareBuffer_Format.
+    uint64_t    usage;      ///< Combination of AHardwareBuffer_UsageFlags.
     uint32_t    stride;     ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
     uint32_t    rfu0;       ///< Initialize to zero, reserved for future use.
     uint64_t    rfu1;       ///< Initialize to zero, reserved for future use.
 } AHardwareBuffer_Desc;
 
+/**
+ * Opaque handle for a native hardware buffer.
+ */
 typedef struct AHardwareBuffer AHardwareBuffer;
 
 #if __ANDROID_API__ >= 26
 
 /**
- * Allocates a buffer that backs an AHardwareBuffer using the passed
- * AHardwareBuffer_Desc.
+ * Allocates a buffer that matches the passed AHardwareBuffer_Desc.
+ *
+ * If allocation succeeds, the buffer can be used according to the
+ * usage flags specified in its description. If a buffer is used in ways
+ * not compatible with its usage flags, the results are undefined and
+ * may include program termination.
  *
  * \return 0 on success, or an error number of the allocation fails for
  * any reason. The returned buffer has a reference count of 1.
@@ -227,14 +308,16 @@
 int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
         AHardwareBuffer** outBuffer) __INTRODUCED_IN(26);
 /**
- * Acquire a reference on the given AHardwareBuffer object.  This prevents the
- * object from being deleted until the last reference is removed.
+ * Acquire a reference on the given AHardwareBuffer object.
+ *
+ * This prevents the object from being deleted until the last reference
+ * is removed.
  */
 void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
 
 /**
  * Remove a reference that was previously acquired with
- * AHardwareBuffer_acquire().
+ * AHardwareBuffer_acquire() or AHardwareBuffer_allocate().
  */
 void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
 
@@ -246,50 +329,73 @@
         AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26);
 
 /**
- * Lock the AHardwareBuffer for reading or writing, depending on the usage flags
- * passed.  This call may block if the hardware needs to finish rendering or if
- * CPU caches need to be synchronized, or possibly for other implementation-
- * specific reasons.  If fence is not negative, then it specifies a fence file
- * descriptor that will be signaled when the buffer is locked, otherwise the
- * caller will block until the buffer is available.
+ * Lock the AHardwareBuffer for direct CPU access.
  *
- * If \a rect is not NULL, the caller promises to modify only data in the area
- * specified by rect. If rect is NULL, the caller may modify the contents of the
- * entire buffer.
+ * This function can lock the buffer for either reading or writing.
+ * It may block if the hardware needs to finish rendering, if CPU caches
+ * need to be synchronized, or possibly for other implementation-
+ * specific reasons.
  *
- * The content of the buffer outside of the specified rect is NOT modified
- * by this call.
+ * The passed AHardwareBuffer must have one layer, otherwise the call
+ * will fail.
  *
- * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set,
- * then outVirtualAddress is filled with the address of the buffer in virtual
+ * If \a fence is not negative, it specifies a fence file descriptor on
+ * which to wait before locking the buffer. If it's negative, the caller
+ * is responsible for ensuring that writes to the buffer have completed
+ * before calling this function.  Using this parameter is more efficient
+ * than waiting on the fence and then calling this function.
+ *
+ * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*.
+ * If set, then outVirtualAddress is filled with the address of the
+ * buffer in virtual memory. The flags must also be compatible with
+ * usage flags specified at buffer creation: if a read flag is passed,
+ * the buffer must have been created with
+ * AHARDWAREBUFFER_USAGE_CPU_READ_RARELY or
+ * AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN. If a write flag is passed, it
+ * must have been created with AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY or
+ * AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN.
+ *
+ * If \a rect is not NULL, the caller promises to modify only data in
+ * the area specified by rect. If rect is NULL, the caller may modify
+ * the contents of the entire buffer. The content of the buffer outside
+ * of the specified rect is NOT modified by this call.
+ *
+ * It is legal for several different threads to lock a buffer for read
+ * access; none of the threads are blocked.
+ *
+ * Locking a buffer simultaneously for write or read/write is undefined,
+ * but will neither terminate the process nor block the caller.
+ * AHardwareBuffer_lock may return an error or leave the buffer's
+ * content in an indeterminate state.
+ *
+ * If the buffer has AHARDWAREBUFFER_FORMAT_BLOB, it is legal lock it
+ * for reading and writing in multiple threads and/or processes
+ * simultaneously, and the contents of the buffer behave like shared
  * memory.
  *
- * THREADING CONSIDERATIONS:
- *
- * It is legal for several different threads to lock a buffer for read access;
- * none of the threads are blocked.
- *
- * Locking a buffer simultaneously for write or read/write is undefined, but
- * will neither terminate the process nor block the caller; AHardwareBuffer_lock
- * may return an error or leave the buffer's content into an indeterminate
- * state.
- *
- * \return 0 on success, -EINVAL if \a buffer is NULL or if the usage
- * flags are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or an error
- * number of the lock fails for any reason.
+ * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags
+ * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer
+ * has more than one layer. Error number if the lock fails for any other
+ * reason.
  */
 int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
         int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26);
 
 /**
- * Unlock the AHardwareBuffer; must be called after all changes to the buffer
- * are completed by the caller. If fence is not NULL then it will be set to a
- * file descriptor that is signaled when all pending work on the buffer is
- * completed. The caller is responsible for closing the fence when it is no
- * longer needed.
+ * Unlock the AHardwareBuffer from direct CPU access.
  *
- * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
- * number if the unlock fails for any reason.
+ * Must be called after all changes to the buffer are completed by the
+ * caller.  If \a fence is NULL, the function will block until all work
+ * is completed.  Otherwise, \a fence will be set either to a valid file
+ * descriptor or to -1.  The file descriptor will become signaled once
+ * the unlocking is complete and buffer contents are updated.
+ * The caller is responsible for closing the file descriptor once it's
+ * no longer needed.  The value -1 indicates that unlocking has already
+ * completed before the function returned and no further operations are
+ * necessary.
+ *
+ * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if
+ * the unlock fails for any reason.
  */
 int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED_IN(26);
 
@@ -302,7 +408,7 @@
 int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd) __INTRODUCED_IN(26);
 
 /**
- * Receive the AHardwareBuffer from an AF_UNIX socket.
+ * Receive an AHardwareBuffer from an AF_UNIX socket.
  *
  * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
  * number if the operation fails for any reason.
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 6831f91..6730596 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -15,7 +15,13 @@
  */
 
 /**
- * @addtogroup NativeActivity Native Activity
+ * @defgroup ANativeWindow Native Window
+ *
+ * ANativeWindow represents the producer end of an image queue.
+ * It is the C counterpart of the android.view.Surface object in Java,
+ * and can be converted both ways. Depending on the consumer, images
+ * submitted to ANativeWindow can be shown on the display or sent to
+ * other consumers, such as video encoders.
  * @{
  */
 
@@ -41,7 +47,7 @@
  * Legacy window pixel format names, kept for backwards compatibility.
  * New code and APIs should use AHARDWAREBUFFER_FORMAT_*.
  */
-enum {
+enum ANativeWindow_LegacyFormat {
     // NOTE: these values must match the values from graphics/common/x.x/types.hal
 
     /** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/
@@ -95,7 +101,7 @@
     /// memory. This may be >= width.
     int32_t stride;
 
-    /// The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
+    /// The format of the buffer. One of AHardwareBuffer_Format.
     int32_t format;
 
     /// The actual bits.
@@ -151,7 +157,7 @@
  *
  * \param width width of the buffers in pixels.
  * \param height height of the buffers in pixels.
- * \param format one of AHARDWAREBUFFER_FORMAT_* constants.
+ * \param format one of the AHardwareBuffer_Format constants.
  * \return 0 for success, or a negative value on error.
  */
 int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS
index d4393d6..81099e8 100644
--- a/libs/sensor/OWNERS
+++ b/libs/sensor/OWNERS
@@ -1,2 +1,3 @@
 arthuri@google.com
 bduddie@google.com
+bstack@google.com
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 0382479..4aa9f62 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -65,12 +65,11 @@
 {
 }
 
-GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
-        PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage, std::string requestorName)
-    : GraphicBuffer()
-{
-    mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount,
-            usage, std::move(requestorName));
+GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+                             uint32_t inLayerCount, uint64_t inUsage, std::string requestorName)
+      : GraphicBuffer() {
+    mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage,
+                              std::move(requestorName));
 }
 
 // deprecated
@@ -83,15 +82,12 @@
 {
 }
 
-GraphicBuffer::GraphicBuffer(const native_handle_t* handle,
-        HandleWrapMethod method, uint32_t width, uint32_t height,
-        PixelFormat format, uint32_t layerCount,
-        uint64_t usage,
-        uint32_t stride)
-    : GraphicBuffer()
-{
-    mInitCheck = initWithHandle(handle, method, width, height, format,
-            layerCount, usage, stride);
+GraphicBuffer::GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method,
+                             uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+                             uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride)
+      : GraphicBuffer() {
+    mInitCheck = initWithHandle(inHandle, method, inWidth, inHeight, inFormat, inLayerCount,
+                                inUsage, inStride);
 }
 
 GraphicBuffer::~GraphicBuffer()
@@ -183,26 +179,24 @@
     return err;
 }
 
-status_t GraphicBuffer::initWithHandle(const native_handle_t* handle,
-        HandleWrapMethod method, uint32_t width, uint32_t height,
-        PixelFormat format, uint32_t layerCount, uint64_t usage,
-        uint32_t stride)
-{
-    ANativeWindowBuffer::width  = static_cast<int>(width);
-    ANativeWindowBuffer::height = static_cast<int>(height);
-    ANativeWindowBuffer::stride = static_cast<int>(stride);
-    ANativeWindowBuffer::format = format;
-    ANativeWindowBuffer::usage  = usage;
-    ANativeWindowBuffer::usage_deprecated = int(usage);
+status_t GraphicBuffer::initWithHandle(const native_handle_t* inHandle, HandleWrapMethod method,
+                                       uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+                                       uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride) {
+    ANativeWindowBuffer::width = static_cast<int>(inWidth);
+    ANativeWindowBuffer::height = static_cast<int>(inHeight);
+    ANativeWindowBuffer::stride = static_cast<int>(inStride);
+    ANativeWindowBuffer::format = inFormat;
+    ANativeWindowBuffer::usage = inUsage;
+    ANativeWindowBuffer::usage_deprecated = int(inUsage);
 
-    ANativeWindowBuffer::layerCount = layerCount;
+    ANativeWindowBuffer::layerCount = inLayerCount;
 
     mOwner = (method == WRAP_HANDLE) ? ownNone : ownHandle;
 
     if (method == TAKE_UNREGISTERED_HANDLE || method == CLONE_HANDLE) {
         buffer_handle_t importedHandle;
-        status_t err = mBufferMapper.importBuffer(handle, width, height,
-                layerCount, format, usage, stride, &importedHandle);
+        status_t err = mBufferMapper.importBuffer(inHandle, inWidth, inHeight, inLayerCount,
+                                                  inFormat, inUsage, inStride, &importedHandle);
         if (err != NO_ERROR) {
             initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0);
 
@@ -210,15 +204,15 @@
         }
 
         if (method == TAKE_UNREGISTERED_HANDLE) {
-            native_handle_close(handle);
-            native_handle_delete(const_cast<native_handle_t*>(handle));
+            native_handle_close(inHandle);
+            native_handle_delete(const_cast<native_handle_t*>(inHandle));
         }
 
-        handle = importedHandle;
-        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
+        inHandle = importedHandle;
+        mBufferMapper.getTransportSize(inHandle, &mTransportNumFds, &mTransportNumInts);
     }
 
-    ANativeWindowBuffer::handle = handle;
+    ANativeWindowBuffer::handle = inHandle;
 
     return NO_ERROR;
 }
@@ -376,6 +370,10 @@
 
 status_t GraphicBuffer::unflatten(
         void const*& buffer, size_t& size, int const*& fds, size_t& count) {
+    if (size < 12 * sizeof(int)) {
+        android_errorWriteLog(0x534e4554, "114223584");
+        return NO_MEMORY;
+    }
 
     int const* buf = static_cast<int const*>(buffer);
 
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index cc38982..315db11 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -118,18 +118,16 @@
         // cannot be used directly, such as one from hidl_handle.
         CLONE_HANDLE,
     };
-    GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method,
-            uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t layerCount,
-            uint64_t usage, uint32_t stride);
+    GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method, uint32_t inWidth,
+                  uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage,
+                  uint32_t inStride);
 
     // These functions are deprecated because they only take 32 bits of usage
-    GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method,
-            uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t layerCount,
-            uint32_t usage, uint32_t stride)
-        : GraphicBuffer(handle, method, width, height, format, layerCount,
-                static_cast<uint64_t>(usage), stride) {}
+    GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method, uint32_t inWidth,
+                  uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage,
+                  uint32_t inStride)
+          : GraphicBuffer(inHandle, method, inWidth, inHeight, inFormat, inLayerCount,
+                          static_cast<uint64_t>(inUsage), inStride) {}
     GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
             uint32_t inLayerCount, uint32_t inUsage, uint32_t inStride,
             native_handle_t* inHandle, bool keepOwnership);
@@ -226,10 +224,9 @@
             PixelFormat inFormat, uint32_t inLayerCount,
             uint64_t inUsage, std::string requestorName);
 
-    status_t initWithHandle(const native_handle_t* handle,
-            HandleWrapMethod method, uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t layerCount,
-            uint64_t usage, uint32_t stride);
+    status_t initWithHandle(const native_handle_t* inHandle, HandleWrapMethod method,
+                            uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+                            uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride);
 
     void free_handle();
 
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
index 6e303a5..2f14f7c 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
@@ -28,7 +28,7 @@
       return -EALREADY;
     }
 
-    fd_.reset(epoll_create(64));
+    fd_.reset(epoll_create1(EPOLL_CLOEXEC));
 
     if (fd_.get() < 0)
       return -errno;
diff --git a/libs/vr/libpdx/status_tests.cpp b/libs/vr/libpdx/status_tests.cpp
index d4e697c..772c529 100644
--- a/libs/vr/libpdx/status_tests.cpp
+++ b/libs/vr/libpdx/status_tests.cpp
@@ -2,6 +2,8 @@
 
 #include <gtest/gtest.h>
 
+#include <memory>
+
 using android::pdx::ErrorStatus;
 using android::pdx::Status;
 
@@ -84,8 +86,8 @@
   Status<std::unique_ptr<int>> status1;
   Status<std::unique_ptr<int>> status2;
 
-  status1 = Status<std::unique_ptr<int>>{std::unique_ptr<int>{new int{11}}};
-  status2 = Status<std::unique_ptr<int>>{std::unique_ptr<int>{new int{12}}};
+  status1 = Status<std::unique_ptr<int>>{std::make_unique<int>(int{11})};
+  status2 = Status<std::unique_ptr<int>>{std::make_unique<int>(int{12})};
   EXPECT_FALSE(status1.empty());
   EXPECT_FALSE(status2.empty());
   EXPECT_TRUE(status1.ok());
@@ -114,7 +116,7 @@
 }
 
 TEST(Status, Take) {
-  Status<std::unique_ptr<int>> status{std::unique_ptr<int>{new int{123}}};
+  Status<std::unique_ptr<int>> status{std::make_unique<int>(int{123})};
   EXPECT_FALSE(status.empty());
   EXPECT_NE(nullptr, status.get());
 
diff --git a/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp b/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp
index fa0adf0..f72dabc 100644
--- a/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp
+++ b/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp
@@ -66,7 +66,7 @@
   prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name.c_str()), 0, 0, 0);
 }
 
-constexpr uint64_t kNanosPerSecond = 1000000000llu;
+constexpr uint64_t kNanosPerSecond = 1000000000LLU;
 
 uint64_t GetClockNs() {
   timespec t;
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 4dc669b..233e0fc 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -84,9 +84,6 @@
         "-Wno-error=sign-compare", // to fix later
         "-Wno-unused-variable",
     ],
-    cppflags: [
-        "-std=c++1z"
-    ],
     shared_libs: sharedLibraries,
     whole_static_libs: staticLibraries,
     header_libs: headerLibraries,
diff --git a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
index 962c745..1cf5f17 100644
--- a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
+++ b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
@@ -11,7 +11,7 @@
 namespace dvr {
 
 EpollEventDispatcher::EpollEventDispatcher() {
-  epoll_fd_.Reset(epoll_create(64));
+  epoll_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
   if (!epoll_fd_) {
     ALOGE("Failed to create epoll fd: %s", strerror(errno));
     return;
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
index 1d5def5..8bb7e83 100644
--- a/opengl/libagl/state.cpp
+++ b/opengl/libagl/state.cpp
@@ -181,7 +181,7 @@
     case GL_FOG:
     case GL_DEPTH_TEST:
         ogles_invalidate_perspective(c);
-        // fall-through...
+        [[fallthrough]];
     case GL_BLEND:
     case GL_SCISSOR_TEST:
     case GL_ALPHA_TEST:
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index aae8e05..4c5f3e9 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -401,14 +401,14 @@
     switch (format) {
     case GL_PALETTE4_RGB8_OES:
         indexBits = 4;
-        /* FALLTHROUGH */
+        [[fallthrough]];
     case GL_PALETTE8_RGB8_OES:
         entrySize = 3;
         break;
 
     case GL_PALETTE4_RGBA8_OES:
         indexBits = 4;
-        /* FALLTHROUGH */
+        [[fallthrough]];
     case GL_PALETTE8_RGBA8_OES:
         entrySize = 4;
         break;
@@ -417,7 +417,7 @@
     case GL_PALETTE4_RGBA4_OES:
     case GL_PALETTE4_RGB5_A1_OES:
         indexBits = 4;
-        /* FALLTHROUGH */
+        [[fallthrough]];
     case GL_PALETTE8_R5_G6_B5_OES:
     case GL_PALETTE8_RGBA4_OES:
     case GL_PALETTE8_RGB5_A1_OES:
@@ -446,14 +446,14 @@
     switch (format) {
     case GL_PALETTE4_RGB8_OES:
         indexBits = 4;
-        /* FALLTHROUGH */
+        [[fallthrough]];
     case GL_PALETTE8_RGB8_OES:
         entrySize = 3;
         break;
 
     case GL_PALETTE4_RGBA8_OES:
         indexBits = 4;
-        /* FALLTHROUGH */
+        [[fallthrough]];
     case GL_PALETTE8_RGBA8_OES:
         entrySize = 4;
         break;
@@ -462,7 +462,7 @@
     case GL_PALETTE4_RGBA4_OES:
     case GL_PALETTE4_RGB5_A1_OES:
         indexBits = 4;
-        /* FALLTHROUGH */
+        [[fallthrough]];
     case GL_PALETTE8_R5_G6_B5_OES:
     case GL_PALETTE8_RGBA4_OES:
     case GL_PALETTE8_RGB5_A1_OES:
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 42049a4..e824238 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -482,58 +482,35 @@
 }
 
 // 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);
-        }
-    }
-
-    // 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);
-        }
-    }
-
-    // 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")) {
+                      "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_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_bt2020_linear")) {
         colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT);
     }
     if (findExtension(dp->disp.queryString.extensions,
-                          "EGL_EXT_gl_colorspace_bt2020_pq")) {
+                      "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")) {
+                      "EGL_EXT_gl_colorspace_display_p3_linear")) {
         colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT);
     }
     return colorSpaces;
@@ -543,19 +520,32 @@
 // If there is no color space attribute in attrib_list, colorSpace is left
 // unmodified.
 static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window,
-                                    android_pixel_format format, const EGLint* attrib_list,
-                                    EGLint* colorSpace,
+                                    const EGLint* attrib_list, EGLint* colorSpace,
                                     std::vector<EGLint>* strippedAttribList) {
     for (const EGLint* 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 = 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 (attr[1] == driverColorSpace) {
                     copyAttribute = true;
@@ -594,12 +584,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;
@@ -727,10 +717,11 @@
         // now select correct colorspace and dataspace based on user's attribute list
         EGLint colorSpace = EGL_UNKNOWN;
         std::vector<EGLint> strippedAttribList;
-        if (!processAttributes(dp, window, format, attrib_list, &colorSpace,
+        if (!processAttributes(dp, window, attrib_list, &colorSpace,
                                &strippedAttribList)) {
             ALOGE("error invalid colorspace: %d", colorSpace);
-            return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+            return EGL_NO_SURFACE;
         }
         attrib_list = strippedAttribList.data();
 
@@ -745,14 +736,14 @@
         }
 
         android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
-        if (dataSpace != HAL_DATASPACE_UNKNOWN) {
-            int 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.
+        int 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);
         }
 
         // the EGL spec requires that a new EGLSurface default to swap interval
@@ -792,10 +783,10 @@
         // now select a corresponding sRGB format if needed
         EGLint colorSpace = EGL_UNKNOWN;
         std::vector<EGLint> strippedAttribList;
-        if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace,
+        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();
 
@@ -826,10 +817,10 @@
         // 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,
+        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();
 
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/gpuservice/Android.bp b/services/gpuservice/Android.bp
new file mode 100644
index 0000000..47bed65
--- /dev/null
+++ b/services/gpuservice/Android.bp
@@ -0,0 +1,73 @@
+filegroup {
+    name: "gpuservice_sources",
+    srcs: [
+        "GpuService.cpp",
+    ],
+}
+
+filegroup {
+    name: "gpuservice_binary_sources",
+    srcs: ["main_gpuservice.cpp"],
+}
+
+cc_defaults {
+    name: "gpuservice_defaults",
+    cflags: [
+        "-DLOG_TAG=\"GpuService\"",
+        "-Wall",
+        "-Werror",
+        "-Wformat",
+        "-Wthread-safety",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+    srcs: [
+        ":gpuservice_sources",
+    ],
+    include_dirs: [
+        "frameworks/native/vulkan/vkjson",
+        "frameworks/native/vulkan/include",
+    ],
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libutils",
+        "libvulkan",
+    ],
+    static_libs: [
+        "libvkjson",
+    ],
+}
+
+cc_defaults {
+    name: "gpuservice_production_defaults",
+    defaults: ["gpuservice_defaults"],
+    cflags: [
+        "-fvisibility=hidden",
+        "-fwhole-program-vtables", // requires ThinLTO
+    ],
+    lto: {
+        thin: true,
+    },
+}
+
+cc_defaults {
+    name: "gpuservice_binary",
+    defaults: ["gpuservice_defaults"],
+    whole_static_libs: [
+        "libsigchain",
+    ],
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+    ldflags: ["-Wl,--export-dynamic"],
+}
+
+cc_binary {
+    name: "gpuservice",
+    defaults: ["gpuservice_binary"],
+    init_rc: ["gpuservice.rc"],
+    srcs: [":gpuservice_binary_sources"],
+}
diff --git a/services/surfaceflinger/GpuService.cpp b/services/gpuservice/GpuService.cpp
similarity index 84%
rename from services/surfaceflinger/GpuService.cpp
rename to services/gpuservice/GpuService.cpp
index 71052fb..150896c 100644
--- a/services/surfaceflinger/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -23,10 +23,7 @@
 
 namespace android {
 
-// ----------------------------------------------------------------------------
-
-class BpGpuService : public BpInterface<IGpuService>
-{
+class BpGpuService : public BpInterface<IGpuService> {
 public:
     explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
 };
@@ -34,19 +31,15 @@
 IMPLEMENT_META_INTERFACE(GpuService, "android.ui.IGpuService");
 
 status_t BnGpuService::onTransact(uint32_t code, const Parcel& data,
-        Parcel* reply, uint32_t flags)
-{
+        Parcel* reply, uint32_t flags) {
     status_t status;
     switch (code) {
     case SHELL_COMMAND_TRANSACTION: {
         int in = data.readFileDescriptor();
         int out = data.readFileDescriptor();
         int err = data.readFileDescriptor();
-        int argc = data.readInt32();
-        Vector<String16> args;
-        for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
-           args.add(data.readString16());
-        }
+        std::vector<String16> args;
+        data.readString16Vector(&args);
         sp<IBinder> unusedCallback;
         sp<IResultReceiver> resultReceiver;
         if ((status = data.readNullableStrongBinder(&unusedCallback)) != OK)
@@ -64,8 +57,6 @@
     }
 }
 
-// ----------------------------------------------------------------------------
-
 namespace {
     status_t cmd_help(int out);
     status_t cmd_vkjson(int out, int err);
@@ -73,11 +64,10 @@
 
 const char* const GpuService::SERVICE_NAME = "gpu";
 
-GpuService::GpuService() {}
+GpuService::GpuService() = default;
 
 status_t GpuService::shellCommand(int /*in*/, int out, int err,
-        Vector<String16>& args)
-{
+                                  std::vector<String16>& args) {
     ALOGV("GpuService::shellCommand");
     for (size_t i = 0, n = args.size(); i < n; i++)
         ALOGV("  arg[%zu]: '%s'", i, String8(args[i]).string());
@@ -93,8 +83,6 @@
     return BAD_VALUE;
 }
 
-// ----------------------------------------------------------------------------
-
 namespace {
 
 status_t cmd_help(int out) {
diff --git a/services/surfaceflinger/GpuService.h b/services/gpuservice/GpuService.h
similarity index 80%
rename from services/surfaceflinger/GpuService.h
rename to services/gpuservice/GpuService.h
index b8c28d2..e2b396e 100644
--- a/services/surfaceflinger/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_GPUSERVICE_H
 #define ANDROID_GPUSERVICE_H
 
+#include <vector>
+
 #include <binder/IInterface.h>
 #include <cutils/compiler.h>
 
@@ -34,22 +36,21 @@
 class BnGpuService: public BnInterface<IGpuService> {
 protected:
     virtual status_t shellCommand(int in, int out, int err,
-        Vector<String16>& args) = 0;
+                                  std::vector<String16>& args) = 0;
 
-    virtual status_t onTransact(uint32_t code, const Parcel& data,
+    status_t onTransact(uint32_t code, const Parcel& data,
             Parcel* reply, uint32_t flags = 0) override;
 };
 
-class GpuService : public BnGpuService
-{
+class GpuService : public BnGpuService {
 public:
     static const char* const SERVICE_NAME ANDROID_API;
 
     GpuService() ANDROID_API;
 
 protected:
-    virtual status_t shellCommand(int in, int out, int err,
-        Vector<String16>& args) override;
+    status_t shellCommand(int in, int out, int err,
+                          std::vector<String16>& args) override;
 };
 
 } // namespace android
diff --git a/services/gpuservice/gpuservice.rc b/services/gpuservice/gpuservice.rc
new file mode 100644
index 0000000..65a5c27
--- /dev/null
+++ b/services/gpuservice/gpuservice.rc
@@ -0,0 +1,4 @@
+service gpu /system/bin/gpuservice
+    class core
+    user gpu_service
+    group graphics
diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp
new file mode 100644
index 0000000..64aafca
--- /dev/null
+++ b/services/gpuservice/main_gpuservice.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <sys/resource.h>
+#include "GpuService.h"
+
+using namespace android;
+
+int main(int /* argc */, char** /* argv */) {
+    signal(SIGPIPE, SIG_IGN);
+
+    // publish GpuService
+    sp<GpuService> gpuservice = new GpuService();
+    sp<IServiceManager> sm(defaultServiceManager());
+    sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
+
+    // limit the number of binder threads to 4.
+    ProcessState::self()->setThreadPoolMaxThreadCount(4);
+
+    // start the thread pool
+    sp<ProcessState> ps(ProcessState::self());
+    ps->startThreadPool();
+    ps->giveThreadPoolName();
+    IPCThreadState::self()->joinThreadPool();
+
+    return 0;
+}
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index a9e5a43..8871199 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -41,6 +41,8 @@
         "-Wall",
         "-Wextra",
         "-Werror",
+        // Allow implicit fallthroughs in InputReader.cpp until they are fixed.
+        "-Wno-error=implicit-fallthrough",
         "-Wno-unused-parameter",
         // TODO: Move inputflinger to its own process and mark it hidden
         //-fvisibility=hidden
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 4d9a2a0..ccc24b9 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -206,7 +206,7 @@
         mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 
-    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+    mEpollFd = epoll_create1(EPOLL_CLOEXEC);
     LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
 
     mINotifyFd = inotify_init();
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 21a9bce..efa6f88 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2645,7 +2645,7 @@
             // Should not happen during first time configuration.
             ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER");
             mParameters.mode = Parameters::MODE_POINTER;
-            // fall through.
+            [[fallthrough]];
         case Parameters::MODE_POINTER:
             mSource = AINPUT_SOURCE_MOUSE;
             mXPrecision = 1.0f;
@@ -3089,6 +3089,7 @@
         InputMapper(device),
         mSource(0), mDeviceMode(DEVICE_MODE_DISABLED),
         mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0),
+        mPhysicalWidth(-1), mPhysicalHeight(-1), mPhysicalLeft(0), mPhysicalTop(0),
         mSurfaceOrientation(DISPLAY_ORIENTATION_0) {
 }
 
@@ -3596,6 +3597,11 @@
                 break;
             }
 
+            mPhysicalWidth = naturalPhysicalWidth;
+            mPhysicalHeight = naturalPhysicalHeight;
+            mPhysicalLeft = naturalPhysicalLeft;
+            mPhysicalTop = naturalPhysicalTop;
+
             mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
             mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
             mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
@@ -3604,6 +3610,11 @@
             mSurfaceOrientation = mParameters.orientationAware ?
                     mViewport.orientation : DISPLAY_ORIENTATION_0;
         } else {
+            mPhysicalWidth = rawWidth;
+            mPhysicalHeight = rawHeight;
+            mPhysicalLeft = 0;
+            mPhysicalTop = 0;
+
             mSurfaceWidth = rawWidth;
             mSurfaceHeight = rawHeight;
             mSurfaceLeft = 0;
@@ -3914,6 +3925,10 @@
     dump += StringPrintf(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
     dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
     dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
+    dump += StringPrintf(INDENT3 "PhysicalWidth: %dpx\n", mPhysicalWidth);
+    dump += StringPrintf(INDENT3 "PhysicalHeight: %dpx\n", mPhysicalHeight);
+    dump += StringPrintf(INDENT3 "PhysicalLeft: %d\n", mPhysicalLeft);
+    dump += StringPrintf(INDENT3 "PhysicalTop: %d\n", mPhysicalTop);
     dump += StringPrintf(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation);
 }
 
@@ -5118,10 +5133,10 @@
             }
             break;
         case DISPLAY_ORIENTATION_180:
-            x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;
+            x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale;
             y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
-            left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
-            right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
+            left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
+            right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
             bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
             top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
             orientation -= M_PI;
@@ -5130,10 +5145,10 @@
             }
             break;
         case DISPLAY_ORIENTATION_270:
-            x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
+            x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale;
             y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-            left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
-            right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
+            left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
+            right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
             bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
             top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
             orientation += M_PI_2;
@@ -6531,8 +6546,12 @@
 }
 
 bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
+    const float scaledX = x * mXScale;
+    const float scaledY = y * mYScale;
     return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue
-            && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue;
+            && scaledX >= mPhysicalLeft && scaledX <= mPhysicalLeft + mPhysicalWidth
+            && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue
+            && scaledY >= mPhysicalTop && scaledY <= mPhysicalTop + mPhysicalHeight;
 }
 
 const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index cef3212..2f98e69 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -1517,13 +1517,21 @@
     // in the natural orientation.
     // The surface origin specifies how the surface coordinates should be translated
     // to align with the logical display coordinate space.
-    // The orientation may be different from the viewport orientation as it specifies
-    // the rotation of the surface coordinates required to produce the viewport's
-    // requested orientation, so it will depend on whether the device is orientation aware.
     int32_t mSurfaceWidth;
     int32_t mSurfaceHeight;
     int32_t mSurfaceLeft;
     int32_t mSurfaceTop;
+
+    // Similar to the surface coordinates, but in the raw display coordinate space rather than in
+    // the logical coordinate space.
+    int32_t mPhysicalWidth;
+    int32_t mPhysicalHeight;
+    int32_t mPhysicalLeft;
+    int32_t mPhysicalTop;
+
+    // The orientation may be different from the viewport orientation as it specifies
+    // the rotation of the surface coordinates required to produce the viewport's
+    // requested orientation, so it will depend on whether the device is orientation aware.
     int32_t mSurfaceOrientation;
 
     // Translation and scaling factors, orientation-independent.
diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp
index f1d3726..2da2a70 100644
--- a/services/inputflinger/host/InputFlinger.cpp
+++ b/services/inputflinger/host/InputFlinger.cpp
@@ -53,7 +53,7 @@
     if ((uid != AID_SHELL)
             && !PermissionCache::checkPermission(sDumpPermission, pid, uid)) {
         result.appendFormat("Permission Denial: "
-                "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
+                "can't dump InputFlinger from pid=%d, uid=%d\n", pid, uid);
     } else {
         dumpInternal(result);
     }
diff --git a/services/sensorservice/OWNERS b/services/sensorservice/OWNERS
index d4393d6..81099e8 100644
--- a/services/sensorservice/OWNERS
+++ b/services/sensorservice/OWNERS
@@ -1,2 +1,3 @@
 arthuri@google.com
 bduddie@google.com
+bstack@google.com
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index c2bb6ad..ce4daa5 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -8,7 +8,6 @@
         "-Wunused",
         "-Wunreachable-code",
     ],
-    cppflags: ["-std=c++1z"],
 }
 
 cc_defaults {
@@ -27,6 +26,7 @@
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.power@1.0",
+        "android.hardware.power@1.3",
         "libbase",
         "libbinder",
         "libbufferhubqueue",
@@ -49,12 +49,10 @@
         "libtimestats_proto",
         "libui",
         "libutils",
-        "libvulkan",
     ],
     static_libs: [
         "libserviceutils",
         "libtrace_proto",
-        "libvkjson",
         "libvr_manager",
         "libvrflinger",
     ],
@@ -69,6 +67,7 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
+        "android.hardware.power@1.3",
         "libhidlbase",
         "libhidltransport",
         "libhwbinder",
@@ -96,6 +95,7 @@
         "DisplayHardware/HWC2.cpp",
         "DisplayHardware/HWComposer.cpp",
         "DisplayHardware/HWComposerBufferCache.cpp",
+        "DisplayHardware/PowerAdvisor.cpp",
         "DisplayHardware/VirtualDisplaySurface.cpp",
         "DispSync.cpp",
         "Effects/Daltonizer.cpp",
@@ -103,7 +103,6 @@
         "EventLog/EventLog.cpp",
         "EventThread.cpp",
         "FrameTracker.cpp",
-        "GpuService.cpp",
         "Layer.cpp",
         "LayerProtoHelper.cpp",
         "LayerRejecter.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f04bd17..f5b5eda 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -63,7 +63,7 @@
         mRefreshPending(false) {
     ALOGV("Creating Layer %s", name.string());
 
-    mFlinger->getRenderEngine().genTextures(1, &mTextureName);
+    mTextureName = mFlinger->getNewTexture();
     mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
 
     if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false;
@@ -704,13 +704,19 @@
 }
 
 void BufferLayer::onFirstRef() {
+    Layer::onFirstRef();
+
     // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer, true);
     mProducer = new MonitoredProducer(producer, mFlinger, this);
-    mConsumer = new BufferLayerConsumer(consumer,
-            mFlinger->getRenderEngine(), mTextureName, this);
+    {
+        // Grab the SF state lock during this since it's the only safe way to access RenderEngine
+        Mutex::Autolock lock(mFlinger->mStateLock);
+        mConsumer = new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName,
+                                            this);
+    }
     mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
     mConsumer->setContentsChangedListener(this);
     mConsumer->setName(mName);
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 077469b..0b59147 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -170,48 +170,8 @@
         }
     }
 
-    /*
-     * createSurface must be called from the GL thread so that it can
-     * have access to the GL context.
-     */
-    class MessageCreateLayer : public MessageBase {
-        SurfaceFlinger* flinger;
-        Client* client;
-        sp<IBinder>* handle;
-        sp<IGraphicBufferProducer>* gbp;
-        status_t result;
-        const String8& name;
-        uint32_t w, h;
-        PixelFormat format;
-        uint32_t flags;
-        sp<Layer>* parent;
-        int32_t windowType;
-        int32_t ownerUid;
-    public:
-        MessageCreateLayer(SurfaceFlinger* flinger,
-                const String8& name, Client* client,
-                uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
-                sp<IBinder>* handle, int32_t windowType, int32_t ownerUid,
-                sp<IGraphicBufferProducer>* gbp,
-                sp<Layer>* parent)
-            : flinger(flinger), client(client),
-              handle(handle), gbp(gbp), result(NO_ERROR),
-              name(name), w(w), h(h), format(format), flags(flags),
-              parent(parent), windowType(windowType), ownerUid(ownerUid) {
-        }
-        status_t getResult() const { return result; }
-        virtual bool handler() {
-            result = flinger->createLayer(name, client, w, h, format, flags,
-                    windowType, ownerUid, handle, gbp, parent);
-            return true;
-        }
-    };
-
-    sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
-            name, this, w, h, format, flags, handle,
-            windowType, ownerUid, gbp, &parent);
-    mFlinger->postMessageSync(msg);
-    return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
+    return mFlinger->createLayer(name, this, w, h, format, flags, windowType,
+                                 ownerUid, handle, gbp, &parent);
 }
 
 status_t Client::destroySurface(const sp<IBinder>& handle) {
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 543f60a..b352b96 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -35,6 +35,8 @@
     bool isVisible() const override;
 
     void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+
+    bool isCreatedFromMainThread() const override { return true; }
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 7acbd11..37dc27d 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -222,7 +222,13 @@
                 // Pretend that the last time this event was handled at the same frame but with the
                 // new offset to allow for a seamless offset change without double-firing or
                 // skipping.
-                listener.mLastEventTime -= (oldPhase - phase);
+                nsecs_t diff = oldPhase - phase;
+                if (diff > mPeriod / 2) {
+                    diff -= mPeriod;
+                } else if (diff < -mPeriod / 2) {
+                    diff += mPeriod;
+                }
+                listener.mLastEventTime -= diff;
                 mCond.signal();
                 return NO_ERROR;
             }
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 61758b6..1a60c83 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -138,7 +138,7 @@
     }
 
     auto display = std::make_unique<Display>(
-            *mComposer.get(), mCapabilities, displayId, DisplayType::Virtual);
+            *mComposer.get(), mPowerAdvisor, mCapabilities, displayId, DisplayType::Virtual);
     display->setConnected(true);
     *outDisplay = display.get();
     mDisplays.emplace(displayId, std::move(display));
@@ -177,7 +177,7 @@
         }
 
         auto newDisplay = std::make_unique<Display>(
-                *mComposer.get(), mCapabilities, displayId, displayType);
+                *mComposer.get(), mPowerAdvisor, mCapabilities, displayId, displayType);
         newDisplay->setConnected(true);
         mDisplays.emplace(displayId, std::move(newDisplay));
     } else if (connection == Connection::Disconnected) {
@@ -219,10 +219,11 @@
 
 // Display methods
 
-Display::Display(android::Hwc2::Composer& composer,
+Display::Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
                  const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
                  DisplayType type)
       : mComposer(composer),
+        mPowerAdvisor(advisor),
         mCapabilities(capabilities),
         mId(id),
         mIsConnected(false),
@@ -605,6 +606,12 @@
 
 Error Display::setColorMode(ColorMode mode, RenderIntent renderIntent)
 {
+    // When the color mode is switched to DISPLAY_P3, we want to boost the GPU frequency
+    // so that GPU composition can finish in time. When color mode is switched from
+    // DISPLAY_P3, we want to reset GPU frequency.
+    const bool expensiveRenderingExpected = (mode == ColorMode::DISPLAY_P3);
+    mPowerAdvisor.setExpensiveRenderingExpected(mId, expensiveRenderingExpected);
+
     auto intError = mComposer.setColorMode(mId, mode, renderIntent);
     return static_cast<Error>(intError);
 }
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 29d7a47..e423167 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -37,6 +37,8 @@
 #include <unordered_set>
 #include <vector>
 
+#include "PowerAdvisor.h"
+
 namespace android {
     class Fence;
     class FloatRect;
@@ -119,6 +121,7 @@
     std::unique_ptr<android::Hwc2::Composer> mComposer;
     std::unordered_set<Capability> mCapabilities;
     std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays;
+    android::Hwc2::impl::PowerAdvisor mPowerAdvisor;
     bool mRegisteredCallback = false;
 };
 
@@ -126,7 +129,8 @@
 class Display
 {
 public:
-    Display(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
+    Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
+            const std::unordered_set<Capability>& capabilities,
             hwc2_display_t id, DisplayType type);
     ~Display();
 
@@ -282,6 +286,7 @@
     // this HWC2::Display, so these references are guaranteed to be valid for
     // the lifetime of this object.
     android::Hwc2::Composer& mComposer;
+    android::Hwc2::PowerAdvisor& mPowerAdvisor;
     const std::unordered_set<Capability>& mCapabilities;
 
     hwc2_display_t mId;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
new file mode 100644
index 0000000..12bbae2
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "PowerAdvisor"
+
+#include <cinttypes>
+
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+
+#include "PowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+
+PowerAdvisor::~PowerAdvisor() = default;
+
+namespace impl {
+
+namespace V1_0 = android::hardware::power::V1_0;
+using V1_3::PowerHint;
+
+PowerAdvisor::~PowerAdvisor() = default;
+
+PowerAdvisor::PowerAdvisor() = default;
+
+void PowerAdvisor::setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) {
+    if (expected) {
+        mExpensiveDisplays.insert(displayId);
+    } else {
+        mExpensiveDisplays.erase(displayId);
+    }
+
+    const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
+    if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
+        const sp<V1_3::IPower> powerHal = getPowerHal();
+        if (powerHal == nullptr) {
+            return;
+        }
+        auto ret = powerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING,
+                                                expectsExpensiveRendering);
+        // If Power HAL 1.3 was available previously but now fails,
+        // it may restart, so attempt to reconnect next time
+        if (!ret.isOk()) {
+            mReconnectPowerHal = true;
+            return;
+        }
+        mNotifiedExpensiveRendering = expectsExpensiveRendering;
+    }
+}
+
+sp<V1_3::IPower> PowerAdvisor::getPowerHal() {
+    static sp<V1_3::IPower> sPowerHal_1_3 = nullptr;
+    static bool sHasPowerHal_1_3 = true;
+
+    if (mReconnectPowerHal) {
+        sPowerHal_1_3 = nullptr;
+        mReconnectPowerHal = false;
+    }
+
+    // Power HAL 1.3 is not guaranteed to be available, thus we need to query
+    // Power HAL 1.0 first and try to cast it to Power HAL 1.3.
+    // Power HAL 1.0 is always available, thus if we fail to query it, it means
+    // Power HAL is not available temporarily and we should retry later. However,
+    // if Power HAL 1.0 is available and we can't cast it to Power HAL 1.3,
+    // it means Power HAL 1.3 is not available at all, so we should stop trying.
+    if (sHasPowerHal_1_3 && sPowerHal_1_3 == nullptr) {
+        sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
+        if (powerHal_1_0 != nullptr) {
+            // Try to cast to Power HAL 1.3
+            sPowerHal_1_3 =  V1_3::IPower::castFrom(powerHal_1_0);
+            if (sPowerHal_1_3 == nullptr) {
+                ALOGW("No Power HAL 1.3 service in system");
+                sHasPowerHal_1_3 = false;
+            } else {
+                ALOGI("Loaded Power HAL 1.3 service");
+            }
+        }
+    }
+    return sPowerHal_1_3;
+}
+
+} // namespace impl
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
new file mode 100644
index 0000000..573a1a9
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+#include <android/hardware/power/1.3/IPower.h>
+#include <utils/StrongPointer.h>
+
+#include <unordered_set>
+
+namespace android {
+namespace Hwc2 {
+
+class PowerAdvisor {
+public:
+    virtual ~PowerAdvisor();
+
+    virtual void setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) = 0;
+};
+
+namespace impl {
+
+namespace V1_3 = android::hardware::power::V1_3;
+
+// PowerAdvisor is a wrapper around IPower HAL which takes into account the
+// full state of the system when sending out power hints to things like the GPU.
+class PowerAdvisor final : public Hwc2::PowerAdvisor {
+public:
+    PowerAdvisor();
+    ~PowerAdvisor() override;
+
+    void setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) override;
+
+private:
+    sp<V1_3::IPower> getPowerHal();
+
+    std::unordered_set<hwc2_display_t> mExpensiveDisplays;
+    bool mNotifiedExpensiveRendering = false;
+    bool mReconnectPowerHal = false;
+};
+
+} // namespace impl
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1dc3f4c..90e0e9e 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -130,17 +130,26 @@
     // drawing state & current state are identical
     mDrawingState = mCurrentState;
 
-    const auto& hwc = flinger->getHwComposer();
-    const auto& activeConfig = hwc.getActiveConfig(HWC_DISPLAY_PRIMARY);
-    nsecs_t displayPeriod = activeConfig->getVsyncPeriod();
-    mFrameTracker.setDisplayRefreshPeriod(displayPeriod);
-
     CompositorTiming compositorTiming;
     flinger->getCompositorTiming(&compositorTiming);
     mFrameEventHistory.initializeCompositorTiming(compositorTiming);
 }
 
-void Layer::onFirstRef() {}
+void Layer::onFirstRef() NO_THREAD_SAFETY_ANALYSIS {
+    if (!isCreatedFromMainThread()) {
+        // Grab the SF state lock during this since it's the only way to safely access HWC
+        mFlinger->mStateLock.lock();
+    }
+
+    const auto& hwc = mFlinger->getHwComposer();
+    const auto& activeConfig = hwc.getActiveConfig(HWC_DISPLAY_PRIMARY);
+    nsecs_t displayPeriod = activeConfig->getVsyncPeriod();
+    mFrameTracker.setDisplayRefreshPeriod(displayPeriod);
+
+    if (!isCreatedFromMainThread()) {
+        mFlinger->mStateLock.unlock();
+    }
+}
 
 Layer::~Layer() {
     sp<Client> c(mClientRef.promote());
@@ -345,20 +354,25 @@
         win.intersect(s.crop, &win);
     }
 
-    Rect bounds = win;
     const auto& p = mDrawingParent.promote();
+    FloatRect floatWin = win.toFloatRect();
+    FloatRect parentBounds = floatWin;
     if (p != nullptr) {
-        // Look in computeScreenBounds recursive call for explanation of
-        // why we pass false here.
-        bounds = p->computeScreenBounds(false /* reduceTransparentRegion */);
+        // We pass an empty Region here for reasons mirroring that of the case described in
+        // the computeScreenBounds reduceTransparentRegion=false case.
+        parentBounds = p->computeBounds(Region());
     }
 
-    Transform t = getTransform();
+    Transform t = s.active.transform;
 
-    FloatRect floatWin = win.toFloatRect();
-    if (p != nullptr) {
+
+    if (p != nullptr || !s.finalCrop.isEmpty()) {
         floatWin = t.transform(floatWin);
-        floatWin = floatWin.intersect(bounds.toFloatRect());
+        floatWin = floatWin.intersect(parentBounds);
+
+        if (!s.finalCrop.isEmpty()) {
+            floatWin = floatWin.intersect(s.finalCrop.toFloatRect());
+        }
         floatWin = t.inverse().transform(floatWin);
     }
 
@@ -1252,7 +1266,15 @@
     return true;
 }
 
-bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
+bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix,
+        bool allowNonRectPreservingTransforms) {
+    Transform t;
+    t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+
+    if (!allowNonRectPreservingTransforms && !t.preserveRects()) {
+        ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER ignored");
+        return false;
+    }
     mCurrentState.sequence++;
     mCurrentState.requested.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
     mCurrentState.modified = true;
@@ -1977,6 +1999,16 @@
     layerInfo->set_refresh_pending(isBufferLatched());
     layerInfo->set_window_type(state.type);
     layerInfo->set_app_id(state.appId);
+    layerInfo->set_curr_frame(mCurrentFrameNumber);
+
+    for (const auto& pendingState : mPendingStates) {
+        auto barrierLayer = pendingState.barrierLayer.promote();
+        if (barrierLayer != nullptr) {
+            BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
+            barrierLayerProto->set_id(barrierLayer->sequence);
+            barrierLayerProto->set_frame_number(pendingState.frameNumber);
+        }
+    }
 }
 
 void Layer::writeToProto(LayerProto* layerInfo, int32_t hwcId) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 34811fb..2239679 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -258,7 +258,7 @@
     // Set a 2x2 transformation matrix on the layer. This transform
     // will be applied after parent transforms, but before any final
     // producer specified transform.
-    bool setMatrix(const layer_state_t::matrix22_t& matrix);
+    bool setMatrix(const layer_state_t::matrix22_t& matrix, bool allowNonRectPreservingTransforms);
 
     // This second set of geometry attributes are controlled by
     // setGeometryAppliesWithResize, and their default mode is to be
@@ -360,6 +360,11 @@
      */
     virtual bool isFixedSize() const { return true; }
 
+    // Most layers aren't created from the main thread, and therefore need to
+    // grab the SF state lock to access HWC, but ContainerLayer does, so we need
+    // to avoid grabbing the lock again to avoid deadlock
+    virtual bool isCreatedFromMainThread() const { return false; }
+
 
     bool isPendingRemoval() const { return mPendingRemoval; }
 
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 09414fd..c218e4d 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -51,10 +51,6 @@
     mProjectionMatrix = mtx;
 }
 
-void Description::setSaturationMatrix(const mat4& mtx) {
-    mSaturationMatrix = mtx;
-}
-
 void Description::setColorMatrix(const mat4& mtx) {
     mColorMatrix = mtx;
 }
@@ -82,11 +78,6 @@
     return mColorMatrix != identity;
 }
 
-bool Description::hasSaturationMatrix() const {
-    const mat4 identity;
-    return mSaturationMatrix != identity;
-}
-
 const mat4& Description::getColorMatrix() const {
     return mColorMatrix;
 }
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 06eaf35..6ebb340 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -42,14 +42,12 @@
     void disableTexture();
     void setColor(const half4& color);
     void setProjectionMatrix(const mat4& mtx);
-    void setSaturationMatrix(const mat4& mtx);
     void setColorMatrix(const mat4& mtx);
     void setInputTransformMatrix(const mat3& matrix);
     void setOutputTransformMatrix(const mat4& matrix);
     bool hasInputTransformMatrix() const;
     bool hasOutputTransformMatrix() const;
     bool hasColorMatrix() const;
-    bool hasSaturationMatrix() const;
     const mat4& getColorMatrix() const;
 
     void setY410BT2020(bool enable);
@@ -92,7 +90,6 @@
     // projection matrix
     mat4 mProjectionMatrix;
     mat4 mColorMatrix;
-    mat4 mSaturationMatrix;
     mat3 mInputTransformMatrix;
     mat4 mOutputTransformMatrix;
 };
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 0048000..744a70c 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -267,10 +267,6 @@
     mState.setColorMatrix(colorTransform);
 }
 
-void GLES20RenderEngine::setSaturationMatrix(const mat4& saturationMatrix) {
-    mState.setSaturationMatrix(saturationMatrix);
-}
-
 void GLES20RenderEngine::disableTexturing() {
     mState.disableTexture();
 }
@@ -383,11 +379,10 @@
 
         // we need to convert the RGB value to linear space and convert it back when:
         // - there is a color matrix that is not an identity matrix, or
-        // - there is a saturation matrix that is not an identity matrix, or
         // - there is an output transform matrix that is not an identity matrix, or
         // - the input transfer function doesn't match the output transfer function.
-        if (wideColorState.hasColorMatrix() || wideColorState.hasSaturationMatrix() ||
-            wideColorState.hasOutputTransformMatrix() || inputTransfer != outputTransfer) {
+        if (wideColorState.hasColorMatrix() || wideColorState.hasOutputTransformMatrix() ||
+            inputTransfer != outputTransfer) {
             switch (inputTransfer) {
                 case Dataspace::TRANSFER_ST2084:
                     wideColorState.setInputTransferFunction(Description::TransferFunction::ST2084);
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index de5761b..cc8eb1d 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -81,7 +81,6 @@
     virtual void setupLayerBlackedOut();
     virtual void setupFillWithColor(float r, float g, float b, float a);
     virtual void setupColorTransform(const mat4& colorTransform);
-    virtual void setSaturationMatrix(const mat4& saturationMatrix);
     virtual void disableTexturing();
     virtual void disableBlending();
 
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
index 95adaca..fe536f0 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -135,22 +135,13 @@
         glUniform4fv(mColorLoc, 1, color);
     }
     if (mInputTransformMatrixLoc >= 0) {
-        // If the input transform matrix is not identity matrix, we want to merge
-        // the saturation matrix with input transform matrix so that the saturation
-        // matrix is applied at the correct stage.
-        mat4 inputTransformMatrix = mat4(desc.mInputTransformMatrix) * desc.mSaturationMatrix;
+        mat4 inputTransformMatrix = mat4(desc.mInputTransformMatrix);
         glUniformMatrix4fv(mInputTransformMatrixLoc, 1, GL_FALSE, inputTransformMatrix.asArray());
     }
     if (mOutputTransformMatrixLoc >= 0) {
         // The output transform matrix and color matrix can be combined as one matrix
         // that is applied right before applying OETF.
         mat4 outputTransformMatrix = desc.mColorMatrix * desc.mOutputTransformMatrix;
-        // If there is no input transform matrix, we want to merge the saturation
-        // matrix with output transform matrix to avoid extra matrix multiplication
-        // in shader.
-        if (mInputTransformMatrixLoc < 0) {
-            outputTransformMatrix *= desc.mSaturationMatrix;
-        }
         glUniformMatrix4fv(mOutputTransformMatrixLoc, 1, GL_FALSE,
                            outputTransformMatrix.asArray());
     }
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 46b0f0d..fe992f1 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -149,8 +149,7 @@
                  description.hasInputTransformMatrix() ?
                      Key::INPUT_TRANSFORM_MATRIX_ON : Key::INPUT_TRANSFORM_MATRIX_OFF)
             .set(Key::Key::OUTPUT_TRANSFORM_MATRIX_MASK,
-                 description.hasOutputTransformMatrix() || description.hasColorMatrix() ||
-                 (!description.hasInputTransformMatrix() && description.hasSaturationMatrix()) ?
+                 description.hasOutputTransformMatrix() || description.hasColorMatrix() ?
                      Key::OUTPUT_TRANSFORM_MATRIX_ON : Key::OUTPUT_TRANSFORM_MATRIX_OFF);
 
     needs.set(Key::Y410_BT2020_MASK,
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 1196216..1786155 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -113,7 +113,6 @@
     virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
 
     virtual void setupColorTransform(const mat4& /* colorTransform */) = 0;
-    virtual void setSaturationMatrix(const mat4& /* saturationMatrix */) = 0;
 
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
@@ -228,7 +227,6 @@
     void checkErrors() const override;
 
     void setupColorTransform(const mat4& /* colorTransform */) override {}
-    void setSaturationMatrix(const mat4& /* saturationMatrix */) override {}
 
     // internal to RenderEngine
     EGLDisplay getEGLDisplay() const;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 87baf8c..28b447f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -37,6 +37,7 @@
 
 #include <dvr/vr_flinger.h>
 
+#include <ui/ColorSpace.h>
 #include <ui/DebugUtils.h>
 #include <ui/DisplayInfo.h>
 #include <ui/DisplayStatInfo.h>
@@ -222,6 +223,7 @@
         mVisibleRegionsDirty(false),
         mGeometryInvalid(false),
         mAnimCompositionPending(false),
+        mBootStage(BootStage::BOOTLOADER),
         mDebugRegion(0),
         mDebugDDMS(0),
         mDebugDisableHWC(0),
@@ -230,7 +232,6 @@
         mLastSwapBufferTime(0),
         mDebugInTransaction(0),
         mLastTransactionTime(0),
-        mBootFinished(false),
         mForceFullDamage(false),
         mPrimaryDispSync("PrimaryDispSync"),
         mPrimaryHWVsyncEnabled(false),
@@ -331,11 +332,26 @@
     auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
     mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
 
-    property_get("debug.sf.early_phase_offset_ns", value, "0");
-    const int earlyWakeupOffsetOffsetNs = atoi(value);
-    ALOGI_IF(earlyWakeupOffsetOffsetNs != 0, "Enabling separate early offset");
-    mVsyncModulator.setPhaseOffsets(sfVsyncPhaseOffsetNs - earlyWakeupOffsetOffsetNs,
-            sfVsyncPhaseOffsetNs);
+    property_get("debug.sf.early_phase_offset_ns", value, "-1");
+    const int earlySfOffsetNs = atoi(value);
+
+    property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
+    const int earlyGlSfOffsetNs = atoi(value);
+
+    property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
+    const int earlyAppOffsetNs = atoi(value);
+
+    property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
+    const int earlyGlAppOffsetNs = atoi(value);
+
+    const VSyncModulator::Offsets earlyOffsets =
+            {earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
+            earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
+    const VSyncModulator::Offsets earlyGlOffsets =
+            {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
+            earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
+    mVsyncModulator.setPhaseOffsets(earlyOffsets, earlyGlOffsets,
+            {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs});
 
     // We should be reading 'persist.sys.sf.color_saturation' here
     // but since /data may be encrypted, we need to wait until after vold
@@ -482,10 +498,32 @@
 
     sp<LambdaMessage> readProperties = new LambdaMessage([&]() {
         readPersistentProperties();
+        mBootStage = BootStage::FINISHED;
     });
     postMessageAsync(readProperties);
 }
 
+uint32_t SurfaceFlinger::getNewTexture() {
+    {
+        std::lock_guard lock(mTexturePoolMutex);
+        if (!mTexturePool.empty()) {
+            uint32_t name = mTexturePool.back();
+            mTexturePool.pop_back();
+            ATRACE_INT("TexturePoolSize", mTexturePool.size());
+            return name;
+        }
+
+        // The pool was too small, so increase it for the future
+        ++mTexturePoolSize;
+    }
+
+    // The pool was empty, so we need to get a new texture name directly using a
+    // blocking call to the main thread
+    uint32_t name = 0;
+    postMessageSync(new LambdaMessage([&]() { getRenderEngine().genTextures(1, &name); }));
+    return name;
+}
+
 void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
     class MessageDestroyGLTexture : public MessageBase {
         RE::RenderEngine& engine;
@@ -662,7 +700,7 @@
                                                 },
                                                 "sfEventThread");
     mEventQueue->setEventThread(mSFEventThread.get());
-    mVsyncModulator.setEventThread(mSFEventThread.get());
+    mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
 
     // Get a RenderEngine for the given display / config (can't fail)
     getBE().mRenderEngine =
@@ -732,9 +770,24 @@
         ALOGE("Run StartPropertySetThread failed!");
     }
 
-    mLegacySrgbSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
+    // This is a hack. Per definition of getDataspaceSaturationMatrix, the returned matrix
+    // is used to saturate legacy sRGB content. However, to make sure the same color under
+    // Display P3 will be saturated to the same color, we intentionally break the API spec
+    // and apply this saturation matrix on Display P3 content. Unless the risk of applying
+    // such saturation matrix on Display P3 is understood fully, the API should always return
+    // identify matrix.
+    mEnhancedSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
             Dataspace::SRGB_LINEAR);
 
+    // we will apply this on Display P3.
+    if (mEnhancedSaturationMatrix != mat4()) {
+        ColorSpace srgb(ColorSpace::sRGB());
+        ColorSpace displayP3(ColorSpace::DisplayP3());
+        mat4 srgbToP3 = mat4(ColorSpaceConnector(srgb, displayP3).getTransform());
+        mat4 p3ToSrgb = mat4(ColorSpaceConnector(displayP3, srgb).getTransform());
+        mEnhancedSaturationMatrix = srgbToP3 * mEnhancedSaturationMatrix * p3ToSrgb;
+    }
+
     ALOGV("Done initializing");
 }
 
@@ -928,6 +981,21 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
+    if (outViewport == nullptr || display.get() == nullptr) {
+        return BAD_VALUE;
+    }
+
+    sp<const DisplayDevice> device(getDisplayDevice(display));
+    if (device == nullptr) {
+        return BAD_VALUE;
+    }
+
+    *outViewport = device->getViewport();
+
+    return NO_ERROR;
+}
+
 int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
     if (display == nullptr) {
         ALOGE("%s : display is nullptr", __func__);
@@ -1496,7 +1564,7 @@
             bool refreshNeeded = handleMessageTransaction();
             refreshNeeded |= handleMessageInvalidate();
             refreshNeeded |= mRepaintEverything;
-            if (refreshNeeded) {
+            if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
                 // Signal a refresh if a transaction modified the window state,
                 // a new buffer was latched, or if HWC has requested a full
                 // repaint
@@ -1809,6 +1877,17 @@
         getBE().mTotalTime += elapsedTime;
     }
     getBE().mLastSwapTime = currentTime;
+
+    {
+        std::lock_guard lock(mTexturePoolMutex);
+        const size_t refillCount = mTexturePoolSize - mTexturePool.size();
+        if (refillCount > 0) {
+            const size_t offset = mTexturePool.size();
+            mTexturePool.resize(mTexturePoolSize);
+            getRenderEngine().genTextures(refillCount, mTexturePool.data() + offset);
+            ATRACE_INT("TexturePoolSize", mTexturePool.size());
+        }
+    }
 }
 
 void SurfaceFlinger::rebuildLayerStacks() {
@@ -2116,11 +2195,15 @@
         displayDevice->onSwapBuffersCompleted();
         displayDevice->makeCurrent();
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+            sp<Fence> releaseFence = Fence::NO_FENCE;
+
             // The layer buffer from the previous frame (if any) is released
             // by HWC only when the release fence from this frame (if any) is
             // signaled.  Always get the release fence from HWC first.
             auto hwcLayer = layer->getHwcLayer(hwcId);
-            sp<Fence> releaseFence = getBE().mHwc->getLayerReleaseFence(hwcId, hwcLayer);
+            if (hwcId >= 0) {
+                releaseFence = getBE().mHwc->getLayerReleaseFence(hwcId, hwcLayer);
+            }
 
             // If the layer was client composited in the previous frame, we
             // need to merge with the previous client target acquire fence.
@@ -2267,8 +2350,10 @@
         const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
     bool hasWideColorGamut = false;
     std::unordered_map<ColorMode, std::vector<RenderIntent>> hwcColorModes;
+    HdrCapabilities hdrCapabilities;
+    int32_t supportedPerFrameMetadata = 0;
 
-    if (hasWideColorDisplay) {
+    if (hasWideColorDisplay && hwcId >= 0) {
         std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
         for (ColorMode colorMode : modes) {
             switch (colorMode) {
@@ -2287,8 +2372,10 @@
         }
     }
 
-    HdrCapabilities hdrCapabilities;
-    getHwComposer().getHdrCapabilities(hwcId, &hdrCapabilities);
+    if (hwcId >= 0) {
+        getHwComposer().getHdrCapabilities(hwcId, &hdrCapabilities);
+        supportedPerFrameMetadata = getHwComposer().getSupportedPerFrameMetadata(hwcId);
+    }
 
     auto nativeWindowSurface = mCreateNativeWindowSurface(producer);
     auto nativeWindow = nativeWindowSurface->getNativeWindow();
@@ -2322,8 +2409,7 @@
             new DisplayDevice(this, state.type, hwcId, state.isSecure, display, nativeWindow,
                               dispSurface, std::move(renderSurface), displayWidth, displayHeight,
                               hasWideColorGamut, hdrCapabilities,
-                              getHwComposer().getSupportedPerFrameMetadata(hwcId),
-                              hwcColorModes, initialPowerMode);
+                              supportedPerFrameMetadata, hwcColorModes, initialPowerMode);
 
     if (maxFrameBufferAcquiredBuffers >= 3) {
         nativeWindowSurface->preallocateBuffers();
@@ -2855,6 +2941,12 @@
         signalLayerUpdate();
     }
 
+    // enter boot animation on first buffer latch
+    if (CC_UNLIKELY(mBootStage == BootStage::BOOTLOADER && newDataLatched)) {
+        ALOGI("Enter boot animation");
+        mBootStage = BootStage::BOOTANIMATION;
+    }
+
     // Only continue with the refresh if there is actually new work to do
     return !mLayersWithQueuedFrames.empty() && newDataLatched;
 }
@@ -2897,8 +2989,7 @@
     ATRACE_INT("hasClientComposition", hasClientComposition);
 
     bool applyColorMatrix = false;
-    bool needsLegacyColorMatrix = false;
-    bool legacyColorMatrixApplied = false;
+    bool needsEnhancedColorMatrix = false;
 
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
@@ -2915,15 +3006,23 @@
         const bool skipClientColorTransform = getBE().mHwc->hasCapability(
             HWC2::Capability::SkipClientColorTransform);
 
+        mat4 colorMatrix;
         applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
         if (applyColorMatrix) {
-            getRenderEngine().setupColorTransform(mDrawingState.colorMatrix);
+            colorMatrix = mDrawingState.colorMatrix;
         }
 
-        needsLegacyColorMatrix =
+        // The current enhanced saturation matrix is designed to enhance Display P3,
+        // thus we only apply this matrix when the render intent is not colorimetric
+        // and the output color space is Display P3.
+        needsEnhancedColorMatrix =
             (displayDevice->getActiveRenderIntent() >= RenderIntent::ENHANCE &&
-             outputDataspace != Dataspace::UNKNOWN &&
-             outputDataspace != Dataspace::SRGB);
+             outputDataspace == Dataspace::DISPLAY_P3);
+        if (needsEnhancedColorMatrix) {
+            colorMatrix *= mEnhancedSaturationMatrix;
+        }
+
+        getRenderEngine().setupColorTransform(colorMatrix);
 
         if (!displayDevice->makeCurrent()) {
             ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
@@ -2961,22 +3060,17 @@
             }
         }
 
-        if (displayDevice->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) {
-            // just to be on the safe side, we don't set the
-            // scissor on the main display. It should never be needed
-            // anyways (though in theory it could since the API allows it).
-            const Rect& bounds(displayDevice->getBounds());
-            const Rect& scissor(displayDevice->getScissor());
-            if (scissor != bounds) {
-                // scissor doesn't match the screen's dimensions, so we
-                // need to clear everything outside of it and enable
-                // the GL scissor so we don't draw anything where we shouldn't
+        const Rect& bounds(displayDevice->getBounds());
+        const Rect& scissor(displayDevice->getScissor());
+        if (scissor != bounds) {
+            // scissor doesn't match the screen's dimensions, so we
+            // need to clear everything outside of it and enable
+            // the GL scissor so we don't draw anything where we shouldn't
 
-                // enable scissor for this frame
-                const uint32_t height = displayDevice->getHeight();
-                getBE().mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
-                        scissor.getWidth(), scissor.getHeight());
-            }
+            // enable scissor for this frame
+            const uint32_t height = displayDevice->getHeight();
+            getBE().mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
+                                              scissor.getWidth(), scissor.getHeight());
         }
     }
 
@@ -3010,17 +3104,6 @@
                     break;
                 }
                 case HWC2::Composition::Client: {
-                    // switch color matrices lazily
-                    if (layer->isLegacyDataSpace() && needsLegacyColorMatrix) {
-                        if (!legacyColorMatrixApplied) {
-                            getRenderEngine().setSaturationMatrix(mLegacySrgbSaturationMatrix);
-                            legacyColorMatrixApplied = true;
-                        }
-                    } else if (legacyColorMatrixApplied) {
-                        getRenderEngine().setSaturationMatrix(mat4());
-                        legacyColorMatrixApplied = false;
-                    }
-
                     layer->draw(renderArea, clip);
                     break;
                 }
@@ -3033,12 +3116,9 @@
         firstLayer = false;
     }
 
-    if (applyColorMatrix) {
+    if (applyColorMatrix || needsEnhancedColorMatrix) {
         getRenderEngine().setupColorTransform(mat4());
     }
-    if (needsLegacyColorMatrix && legacyColorMatrixApplied) {
-        getRenderEngine().setSaturationMatrix(mat4());
-    }
 
     // disable scissor at the end of the frame
     getBE().mRenderEngine->disableScissor();
@@ -3327,6 +3407,18 @@
     return flags;
 }
 
+bool callingThreadHasUnscopedSurfaceFlingerAccess() {
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+
+    if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
+            !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
+        return false;
+    }
+    return true;
+}
+
 uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState) {
     const layer_state_t& s = composerState.state;
     sp<Client> client(static_cast<Client*>(composerState.client.get()));
@@ -3408,7 +3500,22 @@
             flags |= eTraversalNeeded;
     }
     if (what & layer_state_t::eMatrixChanged) {
-        if (layer->setMatrix(s.matrix))
+        // TODO: b/109894387
+        //
+        // SurfaceFlinger's renderer is not prepared to handle cropping in the face of arbitrary
+        // rotation. To see the problem observe that if we have a square parent, and a child
+        // of the same size, then we rotate the child 45 degrees around it's center, the child
+        // must now be cropped to a non rectangular 8 sided region.
+        //
+        // Of course we can fix this in the future. For now, we are lucky, SurfaceControl is
+        // private API, and the WindowManager only uses rotation in one case, which is on a top
+        // level layer in which cropping is not an issue.
+        //
+        // However given that abuse of rotation matrices could lead to surfaces extending outside
+        // of cropped areas, we need to prevent non-root clients without permission ACCESS_SURFACE_FLINGER
+        // (a.k.a. everyone except WindowManager and tests) from setting non rectangle preserving
+        // transformations.
+        if (layer->setMatrix(s.matrix, callingThreadHasUnscopedSurfaceFlingerAccess()))
             flags |= eTraversalNeeded;
     }
     if (what & layer_state_t::eTransparentRegionChanged) {
@@ -3574,10 +3681,13 @@
     // Tack on our counter whether there is a hit or not, so everyone gets a tag
     String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
 
+    // Grab the state lock since we're accessing mCurrentState
+    Mutex::Autolock lock(mStateLock);
+
     // Loop over layers until we're sure there is no matching name
     while (matchFound) {
         matchFound = false;
-        mDrawingState.traverseInZOrder([&](Layer* layer) {
+        mCurrentState.traverseInZOrder([&](Layer* layer) {
             if (layer->getName() == uniqueName) {
                 matchFound = true;
                 uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
@@ -4207,9 +4317,22 @@
     colorizer.bold(result);
     result.append("DispSync configuration: ");
     colorizer.reset(result);
-    result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, early sf phase %" PRId64
-        " ns, present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
-        vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, mVsyncModulator.getEarlyPhaseOffset(),
+    const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
+    const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
+    result.appendFormat(
+        "app phase %" PRId64 " ns, "
+        "sf phase %" PRId64 " ns, "
+        "early app phase %" PRId64 " ns, "
+        "early sf phase %" PRId64 " ns, "
+        "early app gl phase %" PRId64 " ns, "
+        "early sf gl phase %" PRId64 " ns, "
+        "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+        vsyncPhaseOffsetNs,
+        sfVsyncPhaseOffsetNs,
+        appEarlyOffset,
+        sfEarlyOffset,
+        appEarlyGlOffset,
+        sfEarlyOffset,
         dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
     result.append("\n");
 
@@ -4412,12 +4535,10 @@
         case INJECT_VSYNC:
         {
             // codes that require permission check
-            IPCThreadState* ipc = IPCThreadState::self();
-            const int pid = ipc->getCallingPid();
-            const int uid = ipc->getCallingUid();
-            if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
-                    !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
-                ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+            if (!callingThreadHasUnscopedSurfaceFlingerAccess()) {
+                IPCThreadState* ipc = IPCThreadState::self();
+                ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d",
+                        ipc->getCallingPid(), ipc->getCallingUid());
                 return PERMISSION_DENIED;
             }
             break;
@@ -4717,6 +4838,16 @@
     const sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
     if (CC_UNLIKELY(device == 0)) return BAD_VALUE;
 
+    const Rect& dispScissor = device->getScissor();
+    if (!dispScissor.isEmpty()) {
+        sourceCrop.set(dispScissor);
+        // adb shell screencap will default reqWidth and reqHeight to zeros.
+        if (reqWidth == 0 || reqHeight == 0) {
+            reqWidth = uint32_t(device->getViewport().width());
+            reqHeight = uint32_t(device->getViewport().height());
+        }
+    }
+
     DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation);
 
     auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8566b03..0148ab6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -320,6 +320,10 @@
         return getDefaultDisplayDeviceLocked();
     }
 
+    // Obtains a name from the texture pool, or, if the pool is empty, posts a
+    // synchronous message to the main thread to obtain one on the fly
+    uint32_t getNewTexture();
+
     // utility function to delete a texture on the main thread
     void deleteTextureAsync(uint32_t texture);
 
@@ -425,6 +429,7 @@
                                    const Rect& sourceCrop, float frameScale, bool childrenOnly);
     virtual status_t getDisplayStats(const sp<IBinder>& display,
             DisplayStatInfo* stats);
+    virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport);
     virtual status_t getDisplayConfigs(const sp<IBinder>& display,
             Vector<DisplayInfo>* configs);
     virtual int getActiveConfig(const sp<IBinder>& display);
@@ -808,6 +813,13 @@
     sp<Fence> mPreviousPresentFence = Fence::NO_FENCE;
     bool mHadClientComposition = false;
 
+    enum class BootStage {
+        BOOTLOADER,
+        BOOTANIMATION,
+        FINISHED,
+    };
+    BootStage mBootStage;
+
     struct HotplugEvent {
         hwc2_display_t display;
         HWC2::Connection connection = HWC2::Connection::Invalid;
@@ -828,7 +840,6 @@
     nsecs_t mLastSwapBufferTime;
     volatile nsecs_t mDebugInTransaction;
     nsecs_t mLastTransactionTime;
-    bool mBootFinished;
     bool mForceFullDamage;
     bool mPropagateBackpressure = true;
     std::unique_ptr<SurfaceInterceptor> mInterceptor =
@@ -858,6 +869,13 @@
 
     std::atomic<bool> mRefreshPending{false};
 
+    // We maintain a pool of pre-generated texture names to hand out to avoid
+    // layer creation needing to run on the main thread (which it would
+    // otherwise need to do to access RenderEngine).
+    std::mutex mTexturePoolMutex;
+    uint32_t mTexturePoolSize = 0;
+    std::vector<uint32_t> mTexturePool;
+
     /* ------------------------------------------------------------------------
      * Feature prototyping
      */
@@ -878,9 +896,9 @@
     static bool useVrFlinger;
     std::thread::id mMainThreadId;
 
-    DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::MANAGED;
-    // Applied on sRGB layers when the render intent is non-colorimetric.
-    mat4 mLegacySrgbSaturationMatrix;
+    DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::ENHANCED;
+    // Applied on Display P3 layers when the render intent is non-colorimetric.
+    mat4 mEnhancedSaturationMatrix;
 
     using CreateBufferQueueFunction =
             std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
index bef6b7c..b937f41 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
@@ -17,7 +17,6 @@
     },
 
     cppflags: [
-        "-std=c++1z",
         "-Werror",
         "-Wno-c++98-compat-pedantic",
         "-Wno-disabled-macro-expansion",
diff --git a/services/surfaceflinger/VSyncModulator.h b/services/surfaceflinger/VSyncModulator.h
index d526313..e071a59 100644
--- a/services/surfaceflinger/VSyncModulator.h
+++ b/services/surfaceflinger/VSyncModulator.h
@@ -36,6 +36,11 @@
 
 public:
 
+    struct Offsets {
+        nsecs_t sf;
+        nsecs_t app;
+    };
+
     enum TransactionStart {
         EARLY,
         NORMAL
@@ -43,21 +48,32 @@
 
     // Sets the phase offsets
     //
-    // early: the phase offset when waking up early. May be the same as late, in which case we don't
-    //        shift offsets.
-    // late: the regular sf phase offset.
-    void setPhaseOffsets(nsecs_t early, nsecs_t late) {
-        mEarlyPhaseOffset = early;
-        mLatePhaseOffset = late;
-        mPhaseOffset = late;
+    // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
+    //          as early. May be the same as late, in which case we don't shift offsets.
+    // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition
+    //            and the transaction was marked as early, we'll use sfEarly.
+    // sfLate: The regular SF vsync phase offset.
+    // appEarly: Like sfEarly, but for the app-vsync
+    // appEarlyGl: Like sfEarlyGl, but for the app-vsync.
+    // appLate: The regular app vsync phase offset.
+    void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) {
+        mEarlyOffsets = early;
+        mEarlyGlOffsets = earlyGl;
+        mLateOffsets = late;
+        mOffsets = late;
     }
 
-    nsecs_t getEarlyPhaseOffset() const {
-        return mEarlyPhaseOffset;
+    Offsets getEarlyOffsets() const {
+        return mEarlyOffsets;
     }
 
-    void setEventThread(EventThread* eventThread) {
-        mEventThread = eventThread;
+    Offsets getEarlyGlOffsets() const {
+        return mEarlyGlOffsets;
+    }
+
+    void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) {
+        mSfEventThread = sfEventThread;
+        mAppEventThread = appEventThread;
     }
 
     void setTransactionStart(TransactionStart transactionStart) {
@@ -71,63 +87,70 @@
             return;
         }
         mTransactionStart = transactionStart;
-        updatePhaseOffsets();
+        updateOffsets();
     }
 
     void onTransactionHandled() {
         if (mTransactionStart == TransactionStart::NORMAL) return;
         mTransactionStart = TransactionStart::NORMAL;
-        updatePhaseOffsets();
+        updateOffsets();
     }
 
     void onRefreshed(bool usedRenderEngine) {
-        bool updatePhaseOffsetsNeeded = false;
+        bool updateOffsetsNeeded = false;
         if (mRemainingEarlyFrameCount > 0) {
             mRemainingEarlyFrameCount--;
-            updatePhaseOffsetsNeeded = true;
+            updateOffsetsNeeded = true;
         }
         if (usedRenderEngine != mLastFrameUsedRenderEngine) {
             mLastFrameUsedRenderEngine = usedRenderEngine;
-            updatePhaseOffsetsNeeded = true;
+            updateOffsetsNeeded = true;
         }
-        if (updatePhaseOffsetsNeeded) {
-            updatePhaseOffsets();
+        if (updateOffsetsNeeded) {
+            updateOffsets();
         }
     }
 
 private:
 
-    void updatePhaseOffsets() {
+    void updateOffsets() {
+        const Offsets desired = getOffsets();
+        const Offsets current = mOffsets;
 
-        // Do not change phase offsets if disabled.
-        if (mEarlyPhaseOffset == mLatePhaseOffset) return;
+        bool changed = false;
+        if (desired.sf != current.sf) {
+            mSfEventThread->setPhaseOffset(desired.sf);
+            changed = true;
+        }
+        if (desired.app != current.app) {
+            mAppEventThread->setPhaseOffset(desired.app);
+            changed = true;
+        }
 
-        if (shouldUseEarlyOffset()) {
-            if (mPhaseOffset != mEarlyPhaseOffset) {
-                if (mEventThread) {
-                    mEventThread->setPhaseOffset(mEarlyPhaseOffset);
-                }
-                mPhaseOffset = mEarlyPhaseOffset;
-            }
-        } else {
-            if (mPhaseOffset != mLatePhaseOffset) {
-                if (mEventThread) {
-                    mEventThread->setPhaseOffset(mLatePhaseOffset);
-                }
-                mPhaseOffset = mLatePhaseOffset;
-            }
+        if (changed) {
+            mOffsets = desired;
         }
     }
 
-    bool shouldUseEarlyOffset() {
-        return mTransactionStart == TransactionStart::EARLY || mLastFrameUsedRenderEngine
-                || mRemainingEarlyFrameCount > 0;
+    Offsets getOffsets() {
+        if (mTransactionStart == TransactionStart::EARLY || mRemainingEarlyFrameCount > 0) {
+            return mEarlyOffsets;
+        } else if (mLastFrameUsedRenderEngine) {
+            return mEarlyGlOffsets;
+        } else {
+            return mLateOffsets;
+        }
     }
 
-    nsecs_t mLatePhaseOffset = 0;
-    nsecs_t mEarlyPhaseOffset = 0;
-    EventThread* mEventThread = nullptr;
-    std::atomic<nsecs_t> mPhaseOffset = 0;
+    Offsets mLateOffsets;
+    Offsets mEarlyOffsets;
+    Offsets mEarlyGlOffsets;
+
+    EventThread* mSfEventThread = nullptr;
+    EventThread* mAppEventThread = nullptr;
+
+    std::atomic<Offsets> mOffsets;
+
     std::atomic<TransactionStart> mTransactionStart = TransactionStart::NORMAL;
     std::atomic<bool> mLastFrameUsedRenderEngine = false;
     std::atomic<int> mRemainingEarlyFrameCount = 0;
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 77c6675..edf56ab 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -80,6 +80,10 @@
   optional int32 hwc_composition_type = 35;
   // If it's a buffer layer, indicate if the content is protected
   optional bool is_protected = 36;
+  // Current frame number being rendered.
+  optional uint64 curr_frame = 37;
+  // A list of barriers that the layer is waiting to update state.
+  repeated BarrierLayerProto barrier_layer = 38;
 }
 
 message PositionProto {
@@ -131,3 +135,10 @@
   optional float b = 3;
   optional float a = 4;
 }
+
+message BarrierLayerProto {
+  // layer id the barrier is waiting on.
+  optional int32 id = 1;
+  // frame number the barrier is waiting on.
+  optional uint64 frame_number = 2;
+}
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 8255b41..d0900e9 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -29,7 +29,6 @@
 #include <displayservice/DisplayService.h>
 #include <hidl/LegacySupport.h>
 #include <configstore/Utils.h>
-#include "GpuService.h"
 #include "SurfaceFlinger.h"
 
 using namespace android;
@@ -102,11 +101,7 @@
     // publish surface flinger
     sp<IServiceManager> sm(defaultServiceManager());
     sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
-                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
-
-    // publish GpuService
-    sp<GpuService> gpuservice = new GpuService();
-    sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
+                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
 
     startDisplayService(); // dependency on SF getting registered above
 
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 19af82c..6ad1b87 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -11,6 +11,7 @@
     shared_libs: [
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.power@1.3",
         "libbase",
         "libbinder",
         "libcutils",
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 8c268b2..9949bfa 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -23,6 +23,7 @@
         "EventThreadTest.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
         "mock/DisplayHardware/MockDisplaySurface.cpp",
+        "mock/DisplayHardware/MockPowerAdvisor.cpp",
         "mock/gui/MockGraphicBufferConsumer.cpp",
         "mock/gui/MockGraphicBufferProducer.cpp",
         "mock/MockEventControlThread.cpp",
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index eec505e..558845f 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -149,12 +149,18 @@
      * Wrapper classes for Read-write access to private data to set up
      * preconditions and assert post-conditions.
      */
+    class FakePowerAdvisor : public Hwc2::PowerAdvisor {
+    public:
+        FakePowerAdvisor() = default;
+        ~FakePowerAdvisor() override = default;
+        void setExpensiveRenderingExpected(hwc2_display_t, bool) override { }
+    };
 
     struct HWC2Display : public HWC2::Display {
-        HWC2Display(Hwc2::Composer& composer,
+        HWC2Display(Hwc2::Composer& composer, Hwc2::PowerAdvisor& advisor,
                     const std::unordered_set<HWC2::Capability>& capabilities, hwc2_display_t id,
                     HWC2::DisplayType type)
-              : HWC2::Display(composer, capabilities, id, type) {}
+              : HWC2::Display(composer, advisor, capabilities, id, type) {}
         ~HWC2Display() {
             // Prevents a call to disable vsyncs.
             mType = HWC2::DisplayType::Invalid;
@@ -216,7 +222,14 @@
             return *this;
         }
 
+        auto& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
+            mPowerAdvisor = powerAdvisor;
+            return *this;
+        }
+
         void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) {
+            static FakePowerAdvisor defaultPowerAdvisor;
+            if (mPowerAdvisor == nullptr) mPowerAdvisor = &defaultPowerAdvisor;
             static const std::unordered_set<HWC2::Capability> defaultCapabilities;
             if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
 
@@ -224,8 +237,8 @@
             // not refer to an instance owned by FakeHwcDisplayInjector. This
             // class has temporary lifetime, while the constructed HWC2::Display
             // is much longer lived.
-            auto display = std::make_unique<HWC2Display>(*composer, *mCapabilities, mHwcDisplayId,
-                                                         mHwcDisplayType);
+            auto display = std::make_unique<HWC2Display>(*composer, *mPowerAdvisor, *mCapabilities,
+                                                         mHwcDisplayId, mHwcDisplayType);
 
             auto config = HWC2::Display::Config::Builder(*display, mActiveConfig);
             config.setWidth(mWidth);
@@ -255,6 +268,7 @@
         int32_t mDpiY = DEFAULT_DPI;
         int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG;
         const std::unordered_set<HWC2::Capability>* mCapabilities = nullptr;
+        Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
     };
 
     class FakeDisplayDeviceInjector {
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.cpp
new file mode 100644
index 0000000..8be7077
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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 "MockPowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+PowerAdvisor::PowerAdvisor() = default;
+PowerAdvisor::~PowerAdvisor() = default;
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
new file mode 100644
index 0000000..dc6d83b
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "DisplayHardware/PowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+namespace mock {
+
+class PowerAdvisor : public android::Hwc2::PowerAdvisor {
+public:
+    PowerAdvisor();
+    ~PowerAdvisor() override;
+
+    MOCK_METHOD2(setExpensiveRenderingExpected, void(hwc2_display_t displayId, bool expected));
+};
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/services/utils/tests/PriorityDumper_test.cpp b/services/utils/tests/PriorityDumper_test.cpp
index 90cc6de..2320a90 100644
--- a/services/utils/tests/PriorityDumper_test.cpp
+++ b/services/utils/tests/PriorityDumper_test.cpp
@@ -54,7 +54,7 @@
 };
 
 static void addAll(Vector<String16>& av, const std::vector<std::string>& v) {
-    for (auto element : v) {
+    for (const auto& element : v) {
         av.add(String16(element.c_str()));
     }
 }
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index 4b90031..d775711 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -19,6 +19,8 @@
 #include <hardware/gralloc1.h>
 #include <log/log.h>
 
+#include <memory>
+
 #include "impl/vr_hwc.h"
 #include "impl/vr_composer_client.h"
 
@@ -39,7 +41,7 @@
 
 std::unique_ptr<ComposerCommandEngine>
 VrComposerClient::createCommandEngine() {
-  return std::unique_ptr<VrCommandEngine>(new VrCommandEngine(*this));
+  return std::make_unique<VrCommandEngine>(*this);
 }
 
 VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client)
diff --git a/services/vr/performanced/Android.bp b/services/vr/performanced/Android.bp
new file mode 100644
index 0000000..20301f6
--- /dev/null
+++ b/services/vr/performanced/Android.bp
@@ -0,0 +1,53 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+    name: "performanced_defaults",
+    static_libs: [
+        "libperformance",
+        "libvr_manager",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libpdx_default_transport",
+    ],
+}
+
+cc_binary {
+    name: "performanced",
+    defaults: ["performanced_defaults"],
+    srcs: [
+        "cpu_set.cpp",
+        "main.cpp",
+        "performance_service.cpp",
+        "task.cpp",
+    ],
+    cflags: [
+        "-DLOG_TAG=\"performanced\"",
+        "-DTRACE=0",
+        "-Wall",
+        "-Werror",
+    ],
+    init_rc: ["performanced.rc"],
+}
+
+cc_test {
+    name: "performance_service_tests",
+    defaults: ["performanced_defaults"],
+    srcs: ["performance_service_tests.cpp"],
+}
diff --git a/services/vr/performanced/Android.mk b/services/vr/performanced/Android.mk
deleted file mode 100644
index a548ef0..0000000
--- a/services/vr/performanced/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-sourceFiles := \
-	cpu_set.cpp \
-	main.cpp \
-	performance_service.cpp \
-	task.cpp
-
-staticLibraries := \
-	libperformance \
-	libvr_manager
-
-sharedLibraries := \
-	libbinder \
-	libbase \
-	libcutils \
-	liblog \
-	libutils \
-	libpdx_default_transport \
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(sourceFiles)
-LOCAL_CFLAGS := -DLOG_TAG=\"performanced\"
-LOCAL_CFLAGS += -DTRACE=0
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_STATIC_LIBRARIES := $(staticLibraries)
-LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
-LOCAL_MODULE := performanced
-LOCAL_INIT_RC := performanced.rc
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := performance_service_tests.cpp
-LOCAL_STATIC_LIBRARIES := $(staticLibraries) libgtest_main
-LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
-LOCAL_MODULE := performance_service_tests
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_NATIVE_TEST)
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index 4065785..a24c889 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -12,16 +12,16 @@
 #include <thread>
 #include <utility>
 
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <dvr/performance_client_api.h>
 #include <gtest/gtest.h>
 #include <private/android_filesystem_config.h>
 
 #include "stdio_filebuf.h"
-#include "string_trim.h"
 #include "unique_file.h"
 
-using android::dvr::Trim;
+using android::base::Trim;
 using android::dvr::UniqueFile;
 using android::dvr::stdio_filebuf;
 
diff --git a/services/vr/performanced/string_trim.h b/services/vr/performanced/string_trim.h
deleted file mode 100644
index 7094e9f..0000000
--- a/services/vr/performanced/string_trim.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
-#define ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
-
-#include <functional>
-#include <locale>
-#include <string>
-
-namespace android {
-namespace dvr {
-
-// Trims whitespace from the left side of |subject| and returns the result as a
-// new string.
-inline std::string LeftTrim(std::string subject) {
-  subject.erase(subject.begin(),
-                std::find_if(subject.begin(), subject.end(),
-                             std::not1(std::ptr_fun<int, int>(std::isspace))));
-  return subject;
-}
-
-// Trims whitespace from the right side of |subject| and returns the result as a
-// new string.
-inline std::string RightTrim(std::string subject) {
-  subject.erase(std::find_if(subject.rbegin(), subject.rend(),
-                             std::not1(std::ptr_fun<int, int>(std::isspace)))
-                    .base(),
-                subject.end());
-  return subject;
-}
-
-// Trims whitespace from the both sides of |subject| and returns the result as a
-// new string.
-inline std::string Trim(std::string subject) {
-  subject.erase(subject.begin(),
-                std::find_if(subject.begin(), subject.end(),
-                             std::not1(std::ptr_fun<int, int>(std::isspace))));
-  subject.erase(std::find_if(subject.rbegin(), subject.rend(),
-                             std::not1(std::ptr_fun<int, int>(std::isspace)))
-                    .base(),
-                subject.end());
-  return subject;
-}
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp
index bda1682..2fc96bf 100644
--- a/services/vr/performanced/task.cpp
+++ b/services/vr/performanced/task.cpp
@@ -10,10 +10,10 @@
 #include <memory>
 #include <sstream>
 
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 
 #include "stdio_filebuf.h"
-#include "string_trim.h"
 
 namespace {
 
@@ -102,7 +102,7 @@
 
       // The status file has lines with the format <field>:<value>. Extract the
       // value after the colon.
-      return Trim(line.substr(offset + field.size() + 1));
+      return android::base::Trim(line.substr(offset + field.size() + 1));
     }
   }
 
@@ -123,7 +123,7 @@
       }
 
       std::string key = line.substr(0, offset);
-      std::string value = Trim(line.substr(offset + 1));
+      std::string value = android::base::Trim(line.substr(offset + 1));
 
       ALOGD_IF(TRACE, "Task::ReadStatusFields: key=\"%s\" value=\"%s\"",
                key.c_str(), value.c_str());
@@ -156,7 +156,7 @@
     std::string line = "";
     std::getline(file_stream, line);
 
-    return Trim(line);
+    return android::base::Trim(line);
   } else {
     return "";
   }
diff --git a/vulkan/api/platform.api b/vulkan/api/platform.api
index 41f398d..a7c4c30 100644
--- a/vulkan/api/platform.api
+++ b/vulkan/api/platform.api
@@ -56,3 +56,6 @@
 
 // VK_USE_PLATFORM_XLIB_XRANDR_EXT
 @internal type u64 RROutput
+
+// VK_USE_PLATFORM_FUCHSIA
+@internal type u32 zx_handle_t
\ No newline at end of file
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 5722810..09db37a 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
 // API version (major.minor.patch)
 define VERSION_MAJOR 1
 define VERSION_MINOR 1
-define VERSION_PATCH 86
+define VERSION_PATCH 93
 
 // API limits
 define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -85,9 +85,7 @@
 @extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6
 @extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_NAME         "VK_KHR_wayland_surface"
 
-// 8
-@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_SPEC_VERSION         4
-@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_NAME                 "VK_KHR_mir_surface"
+// 8 - VK_KHR_mir_surface removed
 
 // 9
 @extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6
@@ -149,6 +147,10 @@
 @extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1
 @extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc"
 
+// 29
+@extension("VK_EXT_transform_feedback") define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1
+@extension("VK_EXT_transform_feedback") define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback"
+
 // 34
 @extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
 @extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
@@ -501,6 +503,10 @@
 @extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_SPEC_VERSION 1
 @extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_EXTENSION_NAME "VK_KHR_bind_memory2"
 
+// 159
+@extension("VK_EXT_image_drm_format_modifier") define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1
+@extension("VK_EXT_image_drm_format_modifier") define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier"
+
 // 161
 @extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1
 @extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache"
@@ -518,8 +524,8 @@
 @extension("VK_NV_shading_rate_image") define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image"
 
 // 166
-@extension("VK_NVX_raytracing") define VK_NVX_RAYTRACING_SPEC_VERSION 1
-@extension("VK_NVX_raytracing") define VK_NVX_RAYTRACING_EXTENSION_NAME "VK_NVX_raytracing"
+@extension("VK_NV_ray_tracing") define VK_NV_RAY_TRACING_SPEC_VERSION 3
+@extension("VK_NV_ray_tracing") define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing"
 
 // 167
 @extension("VK_NV_representative_fragment_test") define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 1
@@ -557,6 +563,10 @@
 @extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1
 @extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties"
 
+// 190
+@extension("VK_AMD_memory_overallocation_behavior") define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1
+@extension("VK_AMD_memory_overallocation_behavior") define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior"
+
 // 191
 @extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
 @extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
@@ -597,6 +607,30 @@
 @extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2
 @extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model"
 
+// 213
+@extension("VK_EXT_pci_bus_info") define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 1
+@extension("VK_EXT_pci_bus_info") define VK_EXT_PCI_BUS_INFO_EXENSION_NAME "VK_EXT_pci_bus_info"
+
+// 215
+@extension("VK_FUCHSIA_imagepipe_surface") define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1
+@extension("VK_FUCHSIA_imagepipe_surface") define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface"
+
+// 222
+@extension("VK_EXT_scalar_block_layout") define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1
+@extension("VK_EXT_scalar_block_layout") define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout"
+
+// 224
+@extension("VK_GOOGLE_hlsl_functionality1") define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 0
+@extension("VK_GOOGLE_hlsl_functionality1") define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1"
+
+// 225
+@extension("VK_GOOGLE_decorate_string") define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 0
+@extension("VK_GOOGLE_decorate_string") define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string"
+
+// 247
+@extension("VK_EXT_separate_stencil_usage") define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1
+@extension("VK_EXT_separate_stencil_usage") define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage"
+
 /////////////
 //  Types  //
 /////////////
@@ -669,7 +703,7 @@
 @extension("VK_EXT_validation_cache") @nonDispatchHandle type u64 VkValidationCacheEXT
 
 // 166
-@extension("VK_NVX_raytracing") @nonDispatchHandle type u64 VkAccelerationStructureNVX
+@extension("VK_NV_ray_tracing") @nonDispatchHandle type u64 VkAccelerationStructureNV
 
 /////////////
 //  Enums  //
@@ -724,6 +758,9 @@
 enum VkImageTiling {
     VK_IMAGE_TILING_OPTIMAL                                 = 0x00000000,
     VK_IMAGE_TILING_LINEAR                                  = 0x00000001,
+
+    //@extension("VK_EXT_image_drm_format_modifier") // 159
+    VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT                 = 1000158000,
 }
 
 enum VkImageViewType {
@@ -767,8 +804,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_ray_tracing") // 166
+    VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV            = 1000165000,
 }
 
 enum VkQueryType {
@@ -776,8 +813,11 @@
     VK_QUERY_TYPE_PIPELINE_STATISTICS                       = 0x00000001, /// Optional
     VK_QUERY_TYPE_TIMESTAMP                                 = 0x00000002,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_QUERY_TYPE_COMPACTED_SIZE_NVX                        = 1000165000,
+    //@extension("VK_EXT_transform_feedback") // 29
+    VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT             = 1000028004,
+
+    //@extension("VK_NV_ray_tracing") // 166
+    VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV  = 1000165000,
 }
 
 enum VkBorderColor {
@@ -793,8 +833,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_ray_tracing") // 166
+    VK_PIPELINE_BIND_POINT_RAY_TRACING_NV                   = 1000165000,
 }
 
 enum VkPrimitiveTopology {
@@ -819,6 +859,9 @@
 enum VkIndexType {
     VK_INDEX_TYPE_UINT16                                    = 0x00000000,
     VK_INDEX_TYPE_UINT32                                    = 0x00000001,
+
+    //@extension("VK_NV_ray_tracing") // 166
+    VK_INDEX_TYPE_NONE_NV                                   = 1000165000,
 }
 
 enum VkFilter {
@@ -1417,9 +1460,6 @@
     //@extension("VK_KHR_wayland_surface") // 7
     VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR           = 1000006000,
 
-    //@extension("VK_KHR_mir_surface") // 8
-    VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR               = 1000007000,
-
     //@extension("VK_KHR_android_surface") // 9
     VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR           = 1000008000,
 
@@ -1447,6 +1487,11 @@
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
 
+    //@extension("VK_EXT_transform_feedback") // 29
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT       = 1000028000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT     = 1000028001,
+    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT   = 1000028002,
+
     //@extension("VK_AMD_texture_gather_bias_lod") // 42
     VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD  = 1000041000,
 
@@ -1722,6 +1767,14 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = 1000156004,
     VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR  = 1000156005,
 
+    //@extension("VK_EXT_image_drm_format_modifier") // 159
+    VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT               = 1000158000,
+    VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT                    = 1000158001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT    = 1000158002,
+    VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT        = 1000158003,
+    VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT    = 1000158004,
+    VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT              = 1000158005,
+
     //@extension("VK_KHR_bind_memory2") // 158
     VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR                       = 1000157000,
     VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR                        = 1000157001,
@@ -1743,18 +1796,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_ray_tracing") // 166
+    VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV                   = 1000165000,
+    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV                 = 1000165001,
+    VK_STRUCTURE_TYPE_GEOMETRY_NV                                           = 1000165003,
+    VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV                                 = 1000165004,
+    VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV                                      = 1000165005,
+    VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV            = 1000165006,
+    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV        = 1000165007,
+    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV    = 1000165008,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV             = 1000165009,
+    VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV               = 1000165011,
+    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV                        = 1000165012,
 
     //@extension("VK_NV_representative_fragment_test") // 167
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000,
@@ -1778,12 +1831,18 @@
     //@extension("VK_KHR_shader_atomic_int64") // 181
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR  = 1000180000,
 
+    //@extension("VK_EXT_calibrated_timestamps") // 185
+    VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT                     = 1000184000,
+
     //@extension("VK_KHR_driver_properties") // 197
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR             = 1000196000,
 
     //@extension("VK_AMD_shader_core_properties") // 186
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD        = 1000185000,
 
+    //@extension("VK_AMD_memory_overallocation_behavior") // 190
+    VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD      = 1000189000,
+
     //@extension("VK_EXT_vertex_attribute_divisor") // 191
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT   = 1000190000,
     VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT       = 1000190001,
@@ -1795,6 +1854,18 @@
 
     //@extension("VK_KHR_vulkan_memory_model") // 212
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000,
+
+    //@extension("VK_EXT_pci_bus_info") // 213
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT   = 1000212000,
+
+    //@extension("VK_FUCHSIA_imagepipe_surface") // 215
+    VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA     = 1000214000,
+
+    //@extension("VK_EXT_scalar_block_layout")
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT  = 1000221000,
+
+    //@extension("VK_EXT_separate_stencil_usage") // 247
+    VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT       = 1000246000,
 }
 
 enum VkSubpassContents {
@@ -1857,14 +1928,17 @@
     //@extension("VK_KHR_maintenance1") // 70
     VK_ERROR_OUT_OF_POOL_MEMORY_KHR                         = 0xC4642878, // -1000069000
 
-    //@extension("VK_EXT_global_priority") // 175
-    VK_ERROR_NOT_PERMITTED_EXT                              = 0xC4628E4F, // -1000174001
-
     //@extension("VK_KHR_external_memory") // 73
     VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR                    = 0xC4641CBD, // -1000072003
 
+    //@extension("VK_EXT_image_drm_format_modifier") // 159
+    VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT   = 0xC462CCD0, // -1000158000
+
     //@extension("VK_EXT_descriptor_indexing") // 162
     VK_ERROR_FRAGMENTATION_EXT                              = 0xc462c118, // -1000161000
+
+    //@extension("VK_EXT_global_priority") // 175
+    VK_ERROR_NOT_PERMITTED_EXT                              = 0xC4628E4F, // -1000174001
 }
 
 enum VkDynamicState {
@@ -1956,8 +2030,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_ray_tracing") // 166
+    VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV                = 1000165000,
 }
 
 
@@ -2080,8 +2154,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_ray_tracing") // 166
+    VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT   = 1000165000,
 }
 
 @extension("VK_AMD_rasterization_order") // 19
@@ -2256,22 +2330,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_ray_tracing") // 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_ray_tracing") // 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_ray_tracing") // 166
+enum VkAccelerationStructureTypeNV {
+    VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV             = 0,
+    VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV          = 1,
+}
+
+@extension("VK_NV_ray_tracing") // 166
+enum VkCopyAccelerationStructureModeNV {
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV            = 0,
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV          = 1,
+}
+
+@extension("VK_NV_ray_tracing") // 166
+enum VkAccelerationStructureMemoryRequirementsTypeNV {
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV            = 0,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV     = 1,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV    = 2,
 }
 
 @extension("VK_EXT_global_priority") // 175
@@ -2282,6 +2370,21 @@
     VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT                   = 1024,
 }
 
+@extension("VK_EXT_calibrated_timestamps") // 185
+enum VkTimeDomainEXT {
+    VK_TIME_DOMAIN_DEVICE_EXT                               = 0,
+    VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT                      = 1,
+    VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT                  = 2,
+    VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT            = 3,
+}
+
+@extension("VK_AMD_memory_overallocation_behavior") // 190
+enum VkMemoryOverallocationBehaviorAMD {
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD           = 0,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD           = 1,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD        = 2,
+}
+
 @extension("VK_KHR_driver_properties") // 197
 enum VkDriverIdKHR {
     VK_DRIVER_ID_AMD_PROPRIETARY_KHR                        = 1,
@@ -2293,6 +2396,7 @@
     VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR                = 7,
     VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR                   = 8,
     VK_DRIVER_ID_ARM_PROPRIETARY_KHR                        = 9,
+    VK_DRIVER_ID_GOOGLE_PASTEL_KHR                          = 10,
 }
 
 /////////////////
@@ -2370,9 +2474,14 @@
     //@extension("VK_NV_shading_rate_image") // 165
     VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV                = 0x00800000,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NVX           = 0x00200000,
-    VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVX          = 0x00400000,
+    //@extension("VK_NV_ray_tracing") // 166
+    VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV            = 0x00200000,
+    VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV           = 0x00400000,
+
+    //@extension("VK_EXT_transform_feedback") // 29
+    VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT              = 0x02000000,
+    VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT       = 0x04000000,
+    VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT      = 0x08000000,
 }
 
 /// Buffer usage flags
@@ -2391,8 +2500,12 @@
     //@extension("VK_EXT_conditional_rendering") // 82
     VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT           = 0x00000200,
 
-    //@extension("VK_NVX_raytracing") // 166
-    VK_BUFFER_USAGE_RAYTRACING_BIT_NVX                      = 0x00000400,
+    //@extension("VK_NV_ray_tracing") // 166
+    VK_BUFFER_USAGE_RAY_TRACING_BIT_NV                      = 0x00000400,
+
+    //@extension("VK_EXT_transform_feedback") // 29
+    VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT           = 0x00000800,
+    VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT   = 0x00001000,
 }
 
 /// Buffer creation flags
@@ -2419,13 +2532,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_ray_tracing") // 166
+    VK_SHADER_STAGE_RAYGEN_BIT_NV                           = 0x00000100,
+    VK_SHADER_STAGE_ANY_HIT_BIT_NV                          = 0x00000200,
+    VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV                      = 0x00000400,
+    VK_SHADER_STAGE_MISS_BIT_NV                             = 0x00000800,
+    VK_SHADER_STAGE_INTERSECTION_BIT_NV                     = 0x00001000,
+    VK_SHADER_STAGE_CALLABLE_BIT_NV                         = 0x00002000,
 
     //@extension("VK_NV_mesh_shader") // 203
     VK_SHADER_STAGE_TASK_BIT_NV                             = 0x00000040,
@@ -2523,8 +2636,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_ray_tracing") // 166
+    VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV                 = 0x00000020,
 }
 
 /// Color component flags
@@ -2666,6 +2779,12 @@
     VK_IMAGE_ASPECT_PLANE_0_BIT_KHR                         = 0x00000010,
     VK_IMAGE_ASPECT_PLANE_1_BIT_KHR                         = 0x00000020,
     VK_IMAGE_ASPECT_PLANE_2_BIT_KHR                         = 0x00000040,
+
+    //@extension("VK_EXT_transform_feedback") // 29
+    VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT                  = 0x00000080,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT                  = 0x00000100,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT                  = 0x00000200,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT                  = 0x00000400,
 }
 
 /// Sparse memory bind flags
@@ -2713,12 +2832,19 @@
     //@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_ray_tracing") // 166
+    VK_PIPELINE_STAGE_RAY_TRACING_BIT_NV                    = 0x00200000,
+    VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV   = 0x02000000,
 
     //@extension("VK_NV_mesh_shader") // 203
     VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV                    = 0x00080000,
     VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV                    = 0x00100000,
+
+    //@extension("VK_EXT_transform_feedback") // 29
+    VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT            = 0x01000000,
+
+    //@extension("VK_NV_ray_tracing") // 166
+    VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV   = 0x02000000,
 }
 
 /// Render pass attachment description flags
@@ -3113,12 +3239,6 @@
 //bitfield VkWaylandSurfaceCreateFlagBitsKHR {
 //}
 
-@extension("VK_KHR_mir_surface") // 8
-type VkFlags VkMirSurfaceCreateFlagsKHR
-//@extension("VK_KHR_mir_surface") // 8
-//bitfield VkMirSurfaceCreateFlagBitsKHR {
-//}
-
 @extension("VK_KHR_android_surface") // 9
 type VkFlags VkAndroidSurfaceCreateFlagsKHR
 //@extension("VK_KHR_android_surface") // 9
@@ -3149,6 +3269,12 @@
     VK_DEBUG_REPORT_DEBUG_BIT_EXT                           = 0x00000010,
 }
 
+@extension("VK_EXT_transform_feedback") // 29
+type VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT
+//@extension("VK_EXT_transform_feedback") // 29
+//bitfield VkPipelineRasterizationStateStreamCreateFlagBitsEXT {
+//}
+
 @extension("VK_NV_external_memory_capabilities") // 56
 type VkFlags VkExternalMemoryHandleTypeFlagsNV
 @extension("VK_NV_external_memory_capabilities") // 56
@@ -3397,35 +3523,41 @@
     VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT     = 0x00000008,
 }
 
-@extension("VK_NVX_raytracing") // 166
-type VkFlags VkGeometryFlagsNVX
-@extension("VK_NVX_raytracing") // 166
-bitfield VkGeometryFlagBitsNVX {
-    VK_GEOMETRY_OPAQUE_BIT_NVX                          = 0x00000001,
-    VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NVX = 0x00000002,
+@extension("VK_NV_ray_tracing") // 166
+type VkFlags VkGeometryFlagsNV
+@extension("VK_NV_ray_tracing") // 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_ray_tracing") // 166
+type VkFlags VkGeometryInstanceFlagsNV
+@extension("VK_NV_ray_tracing") // 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_ray_tracing") // 166
+type VkFlags VkBuildAccelerationStructureFlagsNV
+@extension("VK_NV_ray_tracing") // 166
+bitfield VkBuildAccelerationStructureFlagBitsNV {
+    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV         = 0x00000001,
+    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV     = 0x00000002,
+    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV    = 0x00000004,
+    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV    = 0x00000008,
+    VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV           = 0x00000010,
 }
 
+@extension("VK_FUCHSIA_imagepipe_surface") // 215
+type VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA
+//@extension("VK_FUCHSIA_imagepipe_surface") // 215
+//bitfield VkImagePipeSurfaceCreateFlagBitsFUCHSIA {
+//}
+
 //////////////////
 //  Structures  //
 //////////////////
@@ -5237,15 +5369,6 @@
     platform.wl_surface*                        surface
 }
 
-@extension("VK_KHR_mir_surface") // 8
-class VkMirSurfaceCreateInfoKHR {
-    VkStructureType                             sType
-    const void*                                 pNext
-    VkMirSurfaceCreateFlagsKHR                  flags
-    platform.MirConnection*                     connection
-    platform.MirSurface*                        mirSurface
-}
-
 @extension("VK_KHR_android_surface") // 9
 class VkAndroidSurfaceCreateInfoKHR {
     VkStructureType                             sType
@@ -5360,6 +5483,38 @@
     VkBuffer                                    buffer
 }
 
+@extension("VK_EXT_transform_feedback") // 29
+class VkPhysicalDeviceTransformFeedbackFeaturesEXT {
+    VkStructureType                             sType
+    void*                                       pNext
+    VkBool32                                    transformFeedback
+    VkBool32                                    geometryStreams
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+class VkPhysicalDeviceTransformFeedbackPropertiesEXT {
+    VkStructureType                             sType
+    void*                                       pNext
+    u32                                         maxTransformFeedbackStreams
+    u32                                         maxTransformFeedbackBuffers
+    VkDeviceSize                                maxTransformFeedbackBufferSize
+    u32                                         maxTransformFeedbackStreamDataSize
+    u32                                         maxTransformFeedbackBufferDataSize
+    u32                                         maxTransformFeedbackBufferDataStride
+    VkBool32                                    transformFeedbackQueries
+    VkBool32                                    transformFeedbackStreamsLinesTriangles
+    VkBool32                                    transformFeedbackRasterizationStreamSelect
+    VkBool32                                    transformFeedbackDraw
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+class VkPipelineRasterizationStateStreamCreateInfoEXT {
+    VkStructureType                                     sType
+    const void*                                         pNext
+    VkPipelineRasterizationStateStreamCreateFlagsEXT    flags
+    u32                                                 rasterizationStream
+}
+
 @extension("VK_AMD_texture_gather_bias_lod") // 42
 class VkTextureLODGatherFormatPropertiesAMD {
     VkStructureType                             sType
@@ -6599,7 +6754,7 @@
     const void*                                     pNext
     VkDebugUtilsMessengerCreateFlagsEXT             flags
     VkDebugUtilsMessageSeverityFlagsEXT             messageSeverity
-    VkDebugUtilsMessageTypeFlagsEXT                 messageType
+    VkDebugUtilsMessageTypeFlagsEXT                 messageTypes
     PFN_vkDebugUtilsMessengerCallbackEXT            pfnUserCallback
     void*                                           pUserData
 }
@@ -6925,6 +7080,55 @@
     VkDeviceSize                                    memoryOffset
 }
 
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkDrmFormatModifierPropertiesEXT {
+    u64                                             drmFormatModifier
+    u32                                             drmFormatModifierPlaneCount
+    VkFormatFeatureFlags                            drmFormatModifierTilingFeatures
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkDrmFormatModifierPropertiesListEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u32                                             drmFormatModifierCount
+    VkDrmFormatModifierPropertiesEXT*               pDrmFormatModifierProperties
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkPhysicalDeviceImageDrmFormatModifierInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u64                                             drmFormatModifier
+    VkSharingMode                                   sharingMode
+    u32                                             queueFamilyIndexCount
+    const u32*                                      pQueueFamilyIndices
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkImageDrmFormatModifierListCreateInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u32                                             drmFormatModifierCount
+    const u64*                                      pDrmFormatModifiers
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkImageDrmFormatModifierExplicitCreateInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u64                                             drmFormatModifier
+    u32                                             drmFormatModifierPlaneCount
+    const VkSubresourceLayout*                      pPlaneLayouts
+}
+
+@extension("VK_EXT_image_drm_format_modifier") // 159
+class VkImageDrmFormatModifierPropertiesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u64                                             drmFormatModifier
+}
+
 @extension("VK_EXT_validation_cache") // 161
 class VkValidationCacheCreateInfoEXT {
     VkStructureType                                 sType
@@ -7075,22 +7279,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_ray_tracing") // 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_ray_tracing") // 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_ray_tracing") // 166
+class VkGeometryTrianglesNV {
     VkStructureType                                 sType
     const void*                                     pNext
     VkBuffer                                        vertexData
@@ -7106,8 +7322,8 @@
     VkDeviceSize                                    transformOffset
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkGeometryAABBNVX {
+@extension("VK_NV_ray_tracing") // 166
+class VkGeometryAABBNV {
     VkStructureType                                 sType
     const void*                                     pNext
     VkBuffer                                        aabbData
@@ -7116,66 +7332,79 @@
     VkDeviceSize                                    offset
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkGeometryDataNVX {
-    VkGeometryTrianglesNVX                          triangles
-    VkGeometryAABBNVX                               aabbs
+@extension("VK_NV_ray_tracing") // 166
+class VkGeometryDataNV {
+    VkGeometryTrianglesNV                           triangles
+    VkGeometryAABBNV                                aabbs
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkGeometryNVX {
+@extension("VK_NV_ray_tracing") // 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_ray_tracing") // 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_ray_tracing") // 166
+class VkAccelerationStructureCreateInfoNV {
     VkStructureType                                 sType
     const void*                                     pNext
-    VkAccelerationStructureNVX                      accelerationStructure
+    VkDeviceSize                                    compactedSize
+    VkAccelerationStructureInfoNV                   info
+}
+
+@extension("VK_NV_ray_tracing") // 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_ray_tracing") // 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_ray_tracing") // 166
+class VkAccelerationStructureMemoryRequirementsInfoNV {
     VkStructureType                                 sType
     const void*                                     pNext
-    VkAccelerationStructureNVX                      accelerationStructure
+    VkAccelerationStructureMemoryRequirementsTypeNV type
+    VkAccelerationStructureNV                       accelerationStructure
 }
 
-@extension("VK_NVX_raytracing") // 166
-class VkPhysicalDeviceRaytracingPropertiesNVX {
+@extension("VK_NV_ray_tracing") // 166
+class VkPhysicalDeviceRaytracingPropertiesNV {
     VkStructureType                                 sType
     void*                                           pNext
-    u32                                             shaderHeaderSize
+    u32                                             shaderGroupHandleSize
     u32                                             maxRecursionDepth
-    u32                                             maxGeometryCount
+    u32                                             maxShaderGroupStride
+    u32                                             shaderGroupBaseAlignment
+    u64                                             maxGeometryCount
+    u64                                             maxInstanceCount
+    u64                                             maxTriangleCount
+    u32                                             maxDescriptorSetAccelerationStructures
 }
 
 @extension("VK_NV_representative_fragment_test") // 167
@@ -7253,6 +7482,13 @@
     VkBool32                                        shaderSharedInt64Atomics
 }
 
+@extension("VK_EXT_calibrated_timestamps") // 185
+class VkCalibratedTimestampInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkTimeDomainEXT                                 timeDomain
+}
+
 @extension("VK_AMD_shader_core_properties") // 186
 class VkPhysicalDeviceShaderCorePropertiesAMD {
     VkStructureType                                 sType
@@ -7273,6 +7509,13 @@
     u32                                             vgprAllocationGranularity
 }
 
+@extension("VK_AMD_memory_overallocation_behavior") // 190
+class VkDeviceMemoryOverallocationCreateInfoAMD {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkMemoryOverallocationBehaviorAMD               overallocationBehavior
+}
+
 @extension("VK_EXT_vertex_attribute_divisor") // 191
 class VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT {
     VkStructureType                                 sType
@@ -7314,7 +7557,7 @@
 class VkPhysicalDeviceDriverPropertiesKHR {
     VkStructureType                                 sType
     void*                                           pNext
-    u32                                             driverID
+    VkDriverIdKHR                                   driverID
     char[VK_MAX_DRIVER_NAME_SIZE_KHR]               driverName
     char[VK_MAX_DRIVER_INFO_SIZE_KHR]               driverInfo
     VkConformanceVersionKHR                         conformanceVersion
@@ -7413,6 +7656,38 @@
     VkBool32                                        vulkanMemoryModelDeviceScope
 }
 
+@extension("VK_EXT_pci_bus_info") // 213
+class VkPhysicalDevicePCIBusInfoPropertiesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u16                                             pciDomain
+    u8                                              pciBus
+    u8                                              pciDevice
+    u8                                              pciFunction
+}
+
+@extension("VK_FUCHSIA_imagepipe_surface") // 215
+class VkImagePipeSurfaceCreateInfoFUCHSIA {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkImagePipeSurfaceCreateFlagsFUCHSIA            flags
+    platform.zx_handle_t                            imagePipeHandle
+}
+
+@extension("VK_EXT_scalar_block_layout") // 222
+class VkPhysicalDeviceScalarBlockLayoutFeaturesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkBool32                                        scalarBlockLayout
+}
+
+@extension("VK_EXT_separate_stencil_usage") // 247
+class VkImageStencilUsageCreateInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    VkImageUsageFlags                               stencilUsage
+}
+
 
 ////////////////
 //  Commands  //
@@ -10171,25 +10446,6 @@
     return ?
 }
 
-@extension("VK_KHR_mir_surface") // 8
-cmd VkResult vkCreateMirSurfaceKHR(
-        VkInstance                              instance,
-        const VkMirSurfaceCreateInfoKHR*        pCreateInfo,
-        const VkAllocationCallbacks*            pAllocator,
-        VkSurfaceKHR*                           pSurface) {
-    instanceObject := GetInstance(instance)
-    return ?
-}
-
-@extension("VK_KHR_mir_surface") // 8
-cmd VkBool32 vkGetPhysicalDeviceMirPresentationSupportKHR(
-        VkPhysicalDevice                        physicalDevice,
-        u32                                     queueFamilyIndex,
-        platform.MirConnection*                 connection) {
-    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-    return ?
-}
-
 @extension("VK_KHR_android_surface") // 9
 cmd VkResult vkCreateAndroidSurfaceKHR(
         VkInstance                              instance,
@@ -10334,6 +10590,62 @@
         const VkDebugMarkerMarkerInfoEXT*           pMarkerInfo) {
 }
 
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdBindTransformFeedbackBuffersEXT(
+        VkCommandBuffer                             commandBuffer,
+        u32                                         firstBinding,
+        u32                                         bindingCount,
+        const VkBuffer*                             pBuffers,
+        const VkDeviceSize*                         pOffsets,
+        const VkDeviceSize*                         pSizes) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdBeginTransformFeedbackEXT(
+        VkCommandBuffer                             commandBuffer,
+        u32                                         firstCounterBuffer,
+        u32                                         counterBufferCount,
+        const VkBuffer*                             pCounterBuffers,
+        const VkDeviceSize*                         pCounterBufferOffsets) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdEndTransformFeedbackEXT(
+        VkCommandBuffer                             commandBuffer,
+        u32                                         firstCounterBuffer,
+        u32                                         counterBufferCount,
+        const VkBuffer*                             pCounterBuffers,
+        const VkDeviceSize*                         pCounterBufferOffsets) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdBeginQueryIndexedEXT(
+        VkCommandBuffer                             commandBuffer,
+        VkQueryPool                                 queryPool,
+        u32                                         query,
+        VkQueryControlFlags                         flags,
+        u32                                         index) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdEndQueryIndexedEXT(
+        VkCommandBuffer                             commandBuffer,
+        VkQueryPool                                 queryPool,
+        u32                                         query,
+        u32                                         index) {
+}
+
+@extension("VK_EXT_transform_feedback") // 29
+cmd void vkCmdDrawIndirectByteCountEXT(
+        VkCommandBuffer                             commandBuffer,
+        u32                                         instanceCount,
+        u32                                         firstInstance,
+        VkBuffer                                    counterBuffer,
+        VkDeviceSize                                counterBufferOffset,
+        u32                                         counterOffset,
+        u32                                         vertexStride) {
+}
+
 @extension("VK_AMD_draw_indirect_count") // 34
 cmd void vkCmdDrawIndirectCountAMD(
         VkCommandBuffer                             commandBuffer,
@@ -11128,6 +11440,14 @@
     return ?
 }
 
+@extension("VK_EXT_image_drm_format_modifier") // 159
+cmd VkResult vkGetImageDrmFormatModifierPropertiesEXT(
+        VkDevice                                        device,
+        VkImage                                         image,
+        VkImageDrmFormatModifierPropertiesEXT*          pProperties) {
+    return ?
+}
+
 @extension("VK_EXT_validation_cache") // 161
 cmd VkResult vkCreateValidationCacheEXT(
         VkDevice                                    device,
@@ -11185,71 +11505,60 @@
         const VkCoarseSampleOrderCustomNV*          pCustomSampleOrders) {
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkCreateAccelerationStructureNVX(
+@extension("VK_NV_ray_tracing") // 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_ray_tracing") // 166
+cmd void vkDestroyAccelerationStructureNV(
         VkDevice                                    device,
-        VkAccelerationStructureNVX                  accelerationStructure,
+        VkAccelerationStructureNV                   accelerationStructure,
         const VkAllocationCallbacks*                pAllocator) {
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd void vkGetAccelerationStructureMemoryRequirementsNVX(
+@extension("VK_NV_ray_tracing") // 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_ray_tracing") // 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_ray_tracing") // 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_ray_tracing") // 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_ray_tracing") // 166
+cmd void vkCmdTraceRaysNV(
         VkCommandBuffer                             commandBuffer,
         VkBuffer                                    raygenShaderBindingTableBuffer,
         VkDeviceSize                                raygenShaderBindingOffset,
@@ -11259,23 +11568,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_ray_tracing") // 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_ray_tracing") // 166
+cmd VkResult vkGetRaytracingShaderHandlesNV(
         VkDevice                                    device,
         VkPipeline                                  pipeline,
         u32                                         firstGroup,
@@ -11285,26 +11598,27 @@
     return ?
 }
 
-@extension("VK_NVX_raytracing") // 166
-cmd VkResult vkGetAccelerationStructureHandleNVX(
+@extension("VK_NV_ray_tracing") // 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_ray_tracing") // 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_ray_tracing") // 166
+cmd VkResult vkCompileDeferredNV(
         VkDevice                                    device,
         VkPipeline                                  pipeline,
         u32                                         shader) {
@@ -11358,6 +11672,24 @@
         u32                                         marker) {
 }
 
+@extension("VK_EXT_calibrated_timestamps") // 185
+cmd VkResult vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(
+        VkPhysicalDevice                            physicalDevice,
+        u32*                                        pTimeDomainCount,
+        VkTimeDomainEXT*                            pTimeDomains) {
+    return ?
+}
+
+@extension("VK_EXT_calibrated_timestamps") // 185
+cmd VkResult vkGetCalibratedTimestampsEXT(
+        VkDevice                                    device,
+        u32                                         timestampCount,
+        const VkCalibratedTimestampInfoEXT*         pTimestampInfos,
+        u64*                                        pTimestamps,
+        u64*                                        pMaxDeviation) {
+    return ?
+}
+
 @extension("VK_NV_mesh_shader") // 203
 cmd void vkCmdDrawMeshTasksNV(
         VkCommandBuffer                             commandBuffer,
@@ -11406,6 +11738,15 @@
         VkCheckpointDataNV*                         pCheckpointData) {
 }
 
+@extension("VK_FUCHSIA_imagepipe_surface") // 215
+cmd VkResult vkCreateImagePipeSurfaceFUCHSIA(
+        VkInstance                                  instance,
+        const VkImagePipeSurfaceCreateInfoFUCHSIA*  pCreateInfo,
+        const VkAllocationCallbacks*                pAllocator,
+        VkSurfaceKHR*                               pSurface) {
+    return ?
+}
+
 
 ////////////////
 // Validation //
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index d05c849..77da637 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -24,6 +24,10 @@
 #include "vulkan_android.h"
 #endif
 
+#ifdef VK_USE_PLATFORM_FUCHSIA
+#include <zircon/types.h>
+#include "vulkan_fuchsia.h"
+#endif
 
 #ifdef VK_USE_PLATFORM_IOS_MVK
 #include "vulkan_ios.h"
@@ -35,12 +39,6 @@
 #endif
 
 
-#ifdef VK_USE_PLATFORM_MIR_KHR
-#include <mir_toolkit/client_types.h>
-#include "vulkan_mir.h"
-#endif
-
-
 #ifdef VK_USE_PLATFORM_VI_NN
 #include "vulkan_vi.h"
 #endif
diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h
index 39f4dc6..35c0664 100644
--- a/vulkan/include/vulkan/vulkan_core.h
+++ b/vulkan/include/vulkan/vulkan_core.h
@@ -43,11 +43,10 @@
 #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
 #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 // Version of this file
-#define VK_HEADER_VERSION 86
+#define VK_HEADER_VERSION 93
 
 
 #define VK_NULL_HANDLE 0
-        
 
 
 #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
@@ -60,7 +59,6 @@
         #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
 #endif
 #endif
-        
 
 
 typedef uint32_t VkFlags;
@@ -147,6 +145,7 @@
     VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
     VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
     VK_ERROR_INVALID_SHADER_NV = -1000012000,
+    VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000,
     VK_ERROR_FRAGMENTATION_EXT = -1000161000,
     VK_ERROR_NOT_PERMITTED_EXT = -1000174001,
     VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY,
@@ -286,7 +285,6 @@
     VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
     VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
     VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
-    VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
     VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000,
     VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
     VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000,
@@ -297,6 +295,9 @@
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001,
+    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002,
     VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000,
     VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
@@ -398,6 +399,12 @@
     VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002,
     VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000,
     VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000,
+    VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000,
+    VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002,
+    VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003,
+    VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004,
+    VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005,
     VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000,
     VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001,
     VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = 1000161000,
@@ -409,17 +416,17 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002,
     VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005,
-    VK_STRUCTURE_TYPE_RAYTRACING_PIPELINE_CREATE_INFO_NVX = 1000165000,
-    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NVX = 1000165001,
-    VK_STRUCTURE_TYPE_GEOMETRY_INSTANCE_NVX = 1000165002,
-    VK_STRUCTURE_TYPE_GEOMETRY_NVX = 1000165003,
-    VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NVX = 1000165004,
-    VK_STRUCTURE_TYPE_GEOMETRY_AABB_NVX = 1000165005,
-    VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NVX = 1000165006,
-    VK_STRUCTURE_TYPE_DESCRIPTOR_ACCELERATION_STRUCTURE_INFO_NVX = 1000165007,
-    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NVX = 1000165008,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAYTRACING_PROPERTIES_NVX = 1000165009,
-    VK_STRUCTURE_TYPE_HIT_SHADER_MODULE_CREATE_INFO_NVX = 1000165010,
+    VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000,
+    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001,
+    VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003,
+    VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004,
+    VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005,
+    VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006,
+    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007,
+    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009,
+    VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011,
+    VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000,
     VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001,
     VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000,
@@ -428,7 +435,9 @@
     VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000,
+    VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
+    VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000,
     VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002,
@@ -443,6 +452,10 @@
     VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000,
     VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000,
+    VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = 1000221000,
+    VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = 1000246000,
     VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
     VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES,
@@ -811,6 +824,7 @@
 typedef enum VkImageTiling {
     VK_IMAGE_TILING_OPTIMAL = 0,
     VK_IMAGE_TILING_LINEAR = 1,
+    VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000,
     VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL,
     VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR,
     VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1),
@@ -833,7 +847,8 @@
     VK_QUERY_TYPE_OCCLUSION = 0,
     VK_QUERY_TYPE_PIPELINE_STATISTICS = 1,
     VK_QUERY_TYPE_TIMESTAMP = 2,
-    VK_QUERY_TYPE_COMPACTED_SIZE_NVX = 1000165000,
+    VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004,
+    VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000,
     VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION,
     VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP,
     VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1),
@@ -1163,7 +1178,7 @@
     VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9,
     VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10,
     VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000,
-    VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NVX = 1000165000,
+    VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
     VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER,
     VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
     VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1),
@@ -1192,7 +1207,7 @@
 typedef enum VkPipelineBindPoint {
     VK_PIPELINE_BIND_POINT_GRAPHICS = 0,
     VK_PIPELINE_BIND_POINT_COMPUTE = 1,
-    VK_PIPELINE_BIND_POINT_RAYTRACING_NVX = 1000165000,
+    VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = 1000165000,
     VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS,
     VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE,
     VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1),
@@ -1211,6 +1226,7 @@
 typedef enum VkIndexType {
     VK_INDEX_TYPE_UINT16 = 0,
     VK_INDEX_TYPE_UINT32 = 1,
+    VK_INDEX_TYPE_NONE_NV = 1000165000,
     VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16,
     VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32,
     VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1),
@@ -1264,7 +1280,7 @@
     VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,
     VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000,
     VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000,
-    VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX = 1000165000,
+    VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
     VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE,
     VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION,
     VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN,
@@ -1428,10 +1444,12 @@
     VK_PIPELINE_STAGE_HOST_BIT = 0x00004000,
     VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000,
     VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000,
+    VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000,
     VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000,
     VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000,
     VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000,
-    VK_PIPELINE_STAGE_RAYTRACING_BIT_NVX = 0x00200000,
+    VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = 0x00200000,
+    VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000,
     VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000,
     VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000,
     VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
@@ -1447,6 +1465,10 @@
     VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010,
     VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020,
     VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200,
+    VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400,
     VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT,
     VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT,
     VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT,
@@ -1521,8 +1543,10 @@
     VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040,
     VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080,
     VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100,
+    VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800,
+    VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000,
     VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200,
-    VK_BUFFER_USAGE_RAYTRACING_BIT_NVX = 0x00000400,
+    VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = 0x00000400,
     VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkBufferUsageFlagBits;
 typedef VkFlags VkBufferUsageFlags;
@@ -1537,7 +1561,7 @@
     VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004,
     VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008,
     VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010,
-    VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NVX = 0x00000020,
+    VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020,
     VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT,
     VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE,
     VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
@@ -1554,12 +1578,12 @@
     VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020,
     VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F,
     VK_SHADER_STAGE_ALL = 0x7FFFFFFF,
-    VK_SHADER_STAGE_RAYGEN_BIT_NVX = 0x00000100,
-    VK_SHADER_STAGE_ANY_HIT_BIT_NVX = 0x00000200,
-    VK_SHADER_STAGE_CLOSEST_HIT_BIT_NVX = 0x00000400,
-    VK_SHADER_STAGE_MISS_BIT_NVX = 0x00000800,
-    VK_SHADER_STAGE_INTERSECTION_BIT_NVX = 0x00001000,
-    VK_SHADER_STAGE_CALLABLE_BIT_NVX = 0x00002000,
+    VK_SHADER_STAGE_RAYGEN_BIT_NV = 0x00000100,
+    VK_SHADER_STAGE_ANY_HIT_BIT_NV = 0x00000200,
+    VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = 0x00000400,
+    VK_SHADER_STAGE_MISS_BIT_NV = 0x00000800,
+    VK_SHADER_STAGE_INTERSECTION_BIT_NV = 0x00001000,
+    VK_SHADER_STAGE_CALLABLE_BIT_NV = 0x00002000,
     VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040,
     VK_SHADER_STAGE_MESH_BIT_NV = 0x00000080,
     VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
@@ -1643,13 +1667,16 @@
     VK_ACCESS_HOST_WRITE_BIT = 0x00004000,
     VK_ACCESS_MEMORY_READ_BIT = 0x00008000,
     VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,
+    VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000,
+    VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000,
+    VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000,
     VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000,
     VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,
     VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,
     VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000,
     VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000,
-    VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NVX = 0x00200000,
-    VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVX = 0x00400000,
+    VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000,
+    VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000,
     VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkAccessFlagBits;
 typedef VkFlags VkAccessFlags;
@@ -6076,9 +6103,10 @@
     VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = 7,
     VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = 8,
     VK_DRIVER_ID_ARM_PROPRIETARY_KHR = 9,
+    VK_DRIVER_ID_GOOGLE_PASTEL_KHR = 10,
     VK_DRIVER_ID_BEGIN_RANGE_KHR = VK_DRIVER_ID_AMD_PROPRIETARY_KHR,
-    VK_DRIVER_ID_END_RANGE_KHR = VK_DRIVER_ID_ARM_PROPRIETARY_KHR,
-    VK_DRIVER_ID_RANGE_SIZE_KHR = (VK_DRIVER_ID_ARM_PROPRIETARY_KHR - VK_DRIVER_ID_AMD_PROPRIETARY_KHR + 1),
+    VK_DRIVER_ID_END_RANGE_KHR = VK_DRIVER_ID_GOOGLE_PASTEL_KHR,
+    VK_DRIVER_ID_RANGE_SIZE_KHR = (VK_DRIVER_ID_GOOGLE_PASTEL_KHR - VK_DRIVER_ID_AMD_PROPRIETARY_KHR + 1),
     VK_DRIVER_ID_MAX_ENUM_KHR = 0x7FFFFFFF
 } VkDriverIdKHR;
 
@@ -6092,7 +6120,7 @@
 typedef struct VkPhysicalDeviceDriverPropertiesKHR {
     VkStructureType            sType;
     void*                      pNext;
-    uint32_t                   driverID;
+    VkDriverIdKHR              driverID;
     char                       driverName[VK_MAX_DRIVER_NAME_SIZE_KHR];
     char                       driverInfo[VK_MAX_DRIVER_INFO_SIZE_KHR];
     VkConformanceVersionKHR    conformanceVersion;
@@ -6157,7 +6185,7 @@
     VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33,
     VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000,
     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000,
-    VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX_EXT = 1000165000,
+    VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000,
     VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT,
     VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT,
     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT,
@@ -6359,6 +6387,95 @@
 
 
 
+#define VK_EXT_transform_feedback 1
+#define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1
+#define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback"
+
+typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT;
+
+typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           transformFeedback;
+    VkBool32           geometryStreams;
+} VkPhysicalDeviceTransformFeedbackFeaturesEXT;
+
+typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           maxTransformFeedbackStreams;
+    uint32_t           maxTransformFeedbackBuffers;
+    VkDeviceSize       maxTransformFeedbackBufferSize;
+    uint32_t           maxTransformFeedbackStreamDataSize;
+    uint32_t           maxTransformFeedbackBufferDataSize;
+    uint32_t           maxTransformFeedbackBufferDataStride;
+    VkBool32           transformFeedbackQueries;
+    VkBool32           transformFeedbackStreamsLinesTriangles;
+    VkBool32           transformFeedbackRasterizationStreamSelect;
+    VkBool32           transformFeedbackDraw;
+} VkPhysicalDeviceTransformFeedbackPropertiesEXT;
+
+typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT {
+    VkStructureType                                     sType;
+    const void*                                         pNext;
+    VkPipelineRasterizationStateStreamCreateFlagsEXT    flags;
+    uint32_t                                            rasterizationStream;
+} VkPipelineRasterizationStateStreamCreateInfoEXT;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes);
+typedef void (VKAPI_PTR *PFN_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets);
+typedef void (VKAPI_PTR *PFN_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets);
+typedef void (VKAPI_PTR *PFN_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index);
+typedef void (VKAPI_PTR *PFN_vkCmdEndQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index);
+typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdBindTransformFeedbackBuffersEXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    firstBinding,
+    uint32_t                                    bindingCount,
+    const VkBuffer*                             pBuffers,
+    const VkDeviceSize*                         pOffsets,
+    const VkDeviceSize*                         pSizes);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBeginTransformFeedbackEXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    firstCounterBuffer,
+    uint32_t                                    counterBufferCount,
+    const VkBuffer*                             pCounterBuffers,
+    const VkDeviceSize*                         pCounterBufferOffsets);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdEndTransformFeedbackEXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    firstCounterBuffer,
+    uint32_t                                    counterBufferCount,
+    const VkBuffer*                             pCounterBuffers,
+    const VkDeviceSize*                         pCounterBufferOffsets);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdBeginQueryIndexedEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    query,
+    VkQueryControlFlags                         flags,
+    uint32_t                                    index);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdEndQueryIndexedEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkQueryPool                                 queryPool,
+    uint32_t                                    query,
+    uint32_t                                    index);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectByteCountEXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    instanceCount,
+    uint32_t                                    firstInstance,
+    VkBuffer                                    counterBuffer,
+    VkDeviceSize                                counterBufferOffset,
+    uint32_t                                    counterOffset,
+    uint32_t                                    vertexStride);
+#endif
+
 #define VK_AMD_draw_indirect_count 1
 #define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
 #define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
@@ -7341,7 +7458,7 @@
 
 typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)(
     VkDebugUtilsMessageSeverityFlagBitsEXT           messageSeverity,
-    VkDebugUtilsMessageTypeFlagsEXT                  messageType,
+    VkDebugUtilsMessageTypeFlagsEXT                  messageTypes,
     const VkDebugUtilsMessengerCallbackDataEXT*      pCallbackData,
     void*                                            pUserData);
 
@@ -7676,6 +7793,63 @@
 #define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage"
 
 
+#define VK_EXT_image_drm_format_modifier 1
+#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1
+#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier"
+
+typedef struct VkDrmFormatModifierPropertiesEXT {
+    uint64_t                drmFormatModifier;
+    uint32_t                drmFormatModifierPlaneCount;
+    VkFormatFeatureFlags    drmFormatModifierTilingFeatures;
+} VkDrmFormatModifierPropertiesEXT;
+
+typedef struct VkDrmFormatModifierPropertiesListEXT {
+    VkStructureType                      sType;
+    void*                                pNext;
+    uint32_t                             drmFormatModifierCount;
+    VkDrmFormatModifierPropertiesEXT*    pDrmFormatModifierProperties;
+} VkDrmFormatModifierPropertiesListEXT;
+
+typedef struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint64_t           drmFormatModifier;
+    VkSharingMode      sharingMode;
+    uint32_t           queueFamilyIndexCount;
+    const uint32_t*    pQueueFamilyIndices;
+} VkPhysicalDeviceImageDrmFormatModifierInfoEXT;
+
+typedef struct VkImageDrmFormatModifierListCreateInfoEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           drmFormatModifierCount;
+    const uint64_t*    pDrmFormatModifiers;
+} VkImageDrmFormatModifierListCreateInfoEXT;
+
+typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT {
+    VkStructureType               sType;
+    const void*                   pNext;
+    uint64_t                      drmFormatModifier;
+    uint32_t                      drmFormatModifierPlaneCount;
+    const VkSubresourceLayout*    pPlaneLayouts;
+} VkImageDrmFormatModifierExplicitCreateInfoEXT;
+
+typedef struct VkImageDrmFormatModifierPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint64_t           drmFormatModifier;
+} VkImageDrmFormatModifierPropertiesEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetImageDrmFormatModifierPropertiesEXT)(VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetImageDrmFormatModifierPropertiesEXT(
+    VkDevice                                    device,
+    VkImage                                     image,
+    VkImageDrmFormatModifierPropertiesEXT*      pProperties);
+#endif
+
 #define VK_EXT_validation_cache 1
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT)
 
@@ -7940,81 +8114,113 @@
     const VkCoarseSampleOrderCustomNV*          pCustomSampleOrders);
 #endif
 
-#define VK_NVX_raytracing 1
-VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNVX)
+#define VK_NV_ray_tracing 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV)
 
-#define VK_NVX_RAYTRACING_SPEC_VERSION    1
-#define VK_NVX_RAYTRACING_EXTENSION_NAME  "VK_NVX_raytracing"
+#define VK_NV_RAY_TRACING_SPEC_VERSION    2
+#define VK_NV_RAY_TRACING_EXTENSION_NAME  "VK_NV_ray_tracing"
+#define VK_SHADER_UNUSED_NV               (~0U)
 
 
-typedef enum VkGeometryTypeNVX {
-    VK_GEOMETRY_TYPE_TRIANGLES_NVX = 0,
-    VK_GEOMETRY_TYPE_AABBS_NVX = 1,
-    VK_GEOMETRY_TYPE_BEGIN_RANGE_NVX = VK_GEOMETRY_TYPE_TRIANGLES_NVX,
-    VK_GEOMETRY_TYPE_END_RANGE_NVX = VK_GEOMETRY_TYPE_AABBS_NVX,
-    VK_GEOMETRY_TYPE_RANGE_SIZE_NVX = (VK_GEOMETRY_TYPE_AABBS_NVX - VK_GEOMETRY_TYPE_TRIANGLES_NVX + 1),
-    VK_GEOMETRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkGeometryTypeNVX;
+typedef enum VkRayTracingShaderGroupTypeNV {
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = 0,
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = 1,
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = 2,
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_BEGIN_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV,
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_END_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV,
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_RANGE_SIZE_NV = (VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV - VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV + 1),
+    VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkRayTracingShaderGroupTypeNV;
 
-typedef enum VkAccelerationStructureTypeNVX {
-    VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX = 0,
-    VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX = 1,
-    VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NVX = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX,
-    VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NVX = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX,
-    VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NVX = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX + 1),
-    VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkAccelerationStructureTypeNVX;
+typedef enum VkGeometryTypeNV {
+    VK_GEOMETRY_TYPE_TRIANGLES_NV = 0,
+    VK_GEOMETRY_TYPE_AABBS_NV = 1,
+    VK_GEOMETRY_TYPE_BEGIN_RANGE_NV = VK_GEOMETRY_TYPE_TRIANGLES_NV,
+    VK_GEOMETRY_TYPE_END_RANGE_NV = VK_GEOMETRY_TYPE_AABBS_NV,
+    VK_GEOMETRY_TYPE_RANGE_SIZE_NV = (VK_GEOMETRY_TYPE_AABBS_NV - VK_GEOMETRY_TYPE_TRIANGLES_NV + 1),
+    VK_GEOMETRY_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkGeometryTypeNV;
 
-typedef enum VkCopyAccelerationStructureModeNVX {
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX = 0,
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX = 1,
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_BEGIN_RANGE_NVX = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX,
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_END_RANGE_NVX = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX,
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_RANGE_SIZE_NVX = (VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX + 1),
-    VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkCopyAccelerationStructureModeNVX;
+typedef enum VkAccelerationStructureTypeNV {
+    VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0,
+    VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1,
+    VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV,
+    VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV,
+    VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV + 1),
+    VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkAccelerationStructureTypeNV;
+
+typedef enum VkCopyAccelerationStructureModeNV {
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = 0,
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = 1,
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_BEGIN_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV,
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_END_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV,
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_RANGE_SIZE_NV = (VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV + 1),
+    VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkCopyAccelerationStructureModeNV;
+
+typedef enum VkAccelerationStructureMemoryRequirementsTypeNV {
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV,
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV + 1),
+    VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkAccelerationStructureMemoryRequirementsTypeNV;
 
 
-typedef enum VkGeometryFlagBitsNVX {
-    VK_GEOMETRY_OPAQUE_BIT_NVX = 0x00000001,
-    VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NVX = 0x00000002,
-    VK_GEOMETRY_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkGeometryFlagBitsNVX;
-typedef VkFlags VkGeometryFlagsNVX;
+typedef enum VkGeometryFlagBitsNV {
+    VK_GEOMETRY_OPAQUE_BIT_NV = 0x00000001,
+    VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = 0x00000002,
+    VK_GEOMETRY_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkGeometryFlagBitsNV;
+typedef VkFlags VkGeometryFlagsNV;
 
-typedef enum VkGeometryInstanceFlagBitsNVX {
-    VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NVX = 0x00000001,
-    VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_FLIP_WINDING_BIT_NVX = 0x00000002,
-    VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NVX = 0x00000004,
-    VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NVX = 0x00000008,
-    VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkGeometryInstanceFlagBitsNVX;
-typedef VkFlags VkGeometryInstanceFlagsNVX;
+typedef enum VkGeometryInstanceFlagBitsNV {
+    VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = 0x00000001,
+    VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002,
+    VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = 0x00000004,
+    VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = 0x00000008,
+    VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkGeometryInstanceFlagBitsNV;
+typedef VkFlags VkGeometryInstanceFlagsNV;
 
-typedef enum VkBuildAccelerationStructureFlagBitsNVX {
-    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NVX = 0x00000001,
-    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NVX = 0x00000002,
-    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NVX = 0x00000004,
-    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NVX = 0x00000008,
-    VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NVX = 0x00000010,
-    VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
-} VkBuildAccelerationStructureFlagBitsNVX;
-typedef VkFlags VkBuildAccelerationStructureFlagsNVX;
+typedef enum VkBuildAccelerationStructureFlagBitsNV {
+    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = 0x00000001,
+    VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = 0x00000002,
+    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = 0x00000004,
+    VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = 0x00000008,
+    VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = 0x00000010,
+    VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkBuildAccelerationStructureFlagBitsNV;
+typedef VkFlags VkBuildAccelerationStructureFlagsNV;
 
-typedef struct VkRaytracingPipelineCreateInfoNVX {
-    VkStructureType                           sType;
-    const void*                               pNext;
-    VkPipelineCreateFlags                     flags;
-    uint32_t                                  stageCount;
-    const VkPipelineShaderStageCreateInfo*    pStages;
-    const uint32_t*                           pGroupNumbers;
-    uint32_t                                  maxRecursionDepth;
-    VkPipelineLayout                          layout;
-    VkPipeline                                basePipelineHandle;
-    int32_t                                   basePipelineIndex;
-} VkRaytracingPipelineCreateInfoNVX;
+typedef struct VkRayTracingShaderGroupCreateInfoNV {
+    VkStructureType                  sType;
+    const void*                      pNext;
+    VkRayTracingShaderGroupTypeNV    type;
+    uint32_t                         generalShader;
+    uint32_t                         closestHitShader;
+    uint32_t                         anyHitShader;
+    uint32_t                         intersectionShader;
+} VkRayTracingShaderGroupCreateInfoNV;
 
-typedef struct VkGeometryTrianglesNVX {
+typedef struct VkRayTracingPipelineCreateInfoNV {
+    VkStructureType                               sType;
+    const void*                                   pNext;
+    VkPipelineCreateFlags                         flags;
+    uint32_t                                      stageCount;
+    const VkPipelineShaderStageCreateInfo*        pStages;
+    uint32_t                                      groupCount;
+    const VkRayTracingShaderGroupCreateInfoNV*    pGroups;
+    uint32_t                                      maxRecursionDepth;
+    VkPipelineLayout                              layout;
+    VkPipeline                                    basePipelineHandle;
+    int32_t                                       basePipelineIndex;
+} VkRayTracingPipelineCreateInfoNV;
+
+typedef struct VkGeometryTrianglesNV {
     VkStructureType    sType;
     const void*        pNext;
     VkBuffer           vertexData;
@@ -8028,136 +8234,138 @@
     VkIndexType        indexType;
     VkBuffer           transformData;
     VkDeviceSize       transformOffset;
-} VkGeometryTrianglesNVX;
+} VkGeometryTrianglesNV;
 
-typedef struct VkGeometryAABBNVX {
+typedef struct VkGeometryAABBNV {
     VkStructureType    sType;
     const void*        pNext;
     VkBuffer           aabbData;
     uint32_t           numAABBs;
     uint32_t           stride;
     VkDeviceSize       offset;
-} VkGeometryAABBNVX;
+} VkGeometryAABBNV;
 
-typedef struct VkGeometryDataNVX {
-    VkGeometryTrianglesNVX    triangles;
-    VkGeometryAABBNVX         aabbs;
-} VkGeometryDataNVX;
+typedef struct VkGeometryDataNV {
+    VkGeometryTrianglesNV    triangles;
+    VkGeometryAABBNV         aabbs;
+} VkGeometryDataNV;
 
-typedef struct VkGeometryNVX {
-    VkStructureType       sType;
-    const void*           pNext;
-    VkGeometryTypeNVX     geometryType;
-    VkGeometryDataNVX     geometry;
-    VkGeometryFlagsNVX    flags;
-} VkGeometryNVX;
+typedef struct VkGeometryNV {
+    VkStructureType      sType;
+    const void*          pNext;
+    VkGeometryTypeNV     geometryType;
+    VkGeometryDataNV     geometry;
+    VkGeometryFlagsNV    flags;
+} VkGeometryNV;
 
-typedef struct VkAccelerationStructureCreateInfoNVX {
-    VkStructureType                         sType;
-    const void*                             pNext;
-    VkAccelerationStructureTypeNVX          type;
-    VkBuildAccelerationStructureFlagsNVX    flags;
-    VkDeviceSize                            compactedSize;
-    uint32_t                                instanceCount;
-    uint32_t                                geometryCount;
-    const VkGeometryNVX*                    pGeometries;
-} VkAccelerationStructureCreateInfoNVX;
+typedef struct VkAccelerationStructureInfoNV {
+    VkStructureType                        sType;
+    const void*                            pNext;
+    VkAccelerationStructureTypeNV          type;
+    VkBuildAccelerationStructureFlagsNV    flags;
+    uint32_t                               instanceCount;
+    uint32_t                               geometryCount;
+    const VkGeometryNV*                    pGeometries;
+} VkAccelerationStructureInfoNV;
 
-typedef struct VkBindAccelerationStructureMemoryInfoNVX {
-    VkStructureType               sType;
-    const void*                   pNext;
-    VkAccelerationStructureNVX    accelerationStructure;
-    VkDeviceMemory                memory;
-    VkDeviceSize                  memoryOffset;
-    uint32_t                      deviceIndexCount;
-    const uint32_t*               pDeviceIndices;
-} VkBindAccelerationStructureMemoryInfoNVX;
+typedef struct VkAccelerationStructureCreateInfoNV {
+    VkStructureType                  sType;
+    const void*                      pNext;
+    VkDeviceSize                     compactedSize;
+    VkAccelerationStructureInfoNV    info;
+} VkAccelerationStructureCreateInfoNV;
 
-typedef struct VkDescriptorAccelerationStructureInfoNVX {
-    VkStructureType                      sType;
-    const void*                          pNext;
-    uint32_t                             accelerationStructureCount;
-    const VkAccelerationStructureNVX*    pAccelerationStructures;
-} VkDescriptorAccelerationStructureInfoNVX;
+typedef struct VkBindAccelerationStructureMemoryInfoNV {
+    VkStructureType              sType;
+    const void*                  pNext;
+    VkAccelerationStructureNV    accelerationStructure;
+    VkDeviceMemory               memory;
+    VkDeviceSize                 memoryOffset;
+    uint32_t                     deviceIndexCount;
+    const uint32_t*              pDeviceIndices;
+} VkBindAccelerationStructureMemoryInfoNV;
 
-typedef struct VkAccelerationStructureMemoryRequirementsInfoNVX {
-    VkStructureType               sType;
-    const void*                   pNext;
-    VkAccelerationStructureNVX    accelerationStructure;
-} VkAccelerationStructureMemoryRequirementsInfoNVX;
+typedef struct VkWriteDescriptorSetAccelerationStructureNV {
+    VkStructureType                     sType;
+    const void*                         pNext;
+    uint32_t                            accelerationStructureCount;
+    const VkAccelerationStructureNV*    pAccelerationStructures;
+} VkWriteDescriptorSetAccelerationStructureNV;
 
-typedef struct VkPhysicalDeviceRaytracingPropertiesNVX {
+typedef struct VkAccelerationStructureMemoryRequirementsInfoNV {
+    VkStructureType                                    sType;
+    const void*                                        pNext;
+    VkAccelerationStructureMemoryRequirementsTypeNV    type;
+    VkAccelerationStructureNV                          accelerationStructure;
+} VkAccelerationStructureMemoryRequirementsInfoNV;
+
+typedef struct VkPhysicalDeviceRayTracingPropertiesNV {
     VkStructureType    sType;
     void*              pNext;
-    uint32_t           shaderHeaderSize;
+    uint32_t           shaderGroupHandleSize;
     uint32_t           maxRecursionDepth;
-    uint32_t           maxGeometryCount;
-} VkPhysicalDeviceRaytracingPropertiesNVX;
+    uint32_t           maxShaderGroupStride;
+    uint32_t           shaderGroupBaseAlignment;
+    uint64_t           maxGeometryCount;
+    uint64_t           maxInstanceCount;
+    uint64_t           maxTriangleCount;
+    uint32_t           maxDescriptorSetAccelerationStructures;
+} VkPhysicalDeviceRayTracingPropertiesNV;
 
 
-typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNVX)(VkDevice device, const VkAccelerationStructureCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNVX* pAccelerationStructure);
-typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNVX)(VkDevice device, VkAccelerationStructureNVX accelerationStructure, const VkAllocationCallbacks* pAllocator);
-typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
-typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureScratchMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
-typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNVX)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos);
-typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureTypeNVX type, uint32_t instanceCount, VkBuffer instanceData, VkDeviceSize instanceOffset, uint32_t geometryCount, const VkGeometryNVX* pGeometries, VkBuildAccelerationStructureFlagsNVX flags, VkBool32 update, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkBuffer scratch, VkDeviceSize scratchOffset);
-typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkCopyAccelerationStructureModeNVX mode);
-typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNVX)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, uint32_t width, uint32_t height);
-typedef VkResult (VKAPI_PTR *PFN_vkCreateRaytracingPipelinesNVX)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRaytracingPipelineCreateInfoNVX* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
-typedef VkResult (VKAPI_PTR *PFN_vkGetRaytracingShaderHandlesNVX)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData);
-typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNVX)(VkDevice device, VkAccelerationStructureNVX accelerationStructure, size_t dataSize, void* pData);
-typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructurePropertiesNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX accelerationStructure, VkQueryType queryType, VkQueryPool queryPool, uint32_t query);
-typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNVX)(VkDevice device, VkPipeline pipeline, uint32_t shader);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice device, const VkAccelerationStructureCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNV* pAccelerationStructure);
+typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
+typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV* pBindInfos);
+typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset);
+typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeNV mode);
+typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
+typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData);
+typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void* pData);
+typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery);
+typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNV)(VkDevice device, VkPipeline pipeline, uint32_t shader);
 
 #ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNV(
     VkDevice                                    device,
-    const VkAccelerationStructureCreateInfoNVX* pCreateInfo,
+    const VkAccelerationStructureCreateInfoNV*  pCreateInfo,
     const VkAllocationCallbacks*                pAllocator,
-    VkAccelerationStructureNVX*                 pAccelerationStructure);
+    VkAccelerationStructureNV*                  pAccelerationStructure);
 
-VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNVX(
+VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNV(
     VkDevice                                    device,
-    VkAccelerationStructureNVX                  accelerationStructure,
+    VkAccelerationStructureNV                   accelerationStructure,
     const VkAllocationCallbacks*                pAllocator);
 
-VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNVX(
+VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNV(
     VkDevice                                    device,
-    const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo,
+    const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo,
     VkMemoryRequirements2KHR*                   pMemoryRequirements);
 
-VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureScratchMemoryRequirementsNVX(
-    VkDevice                                    device,
-    const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo,
-    VkMemoryRequirements2KHR*                   pMemoryRequirements);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNV(
     VkDevice                                    device,
     uint32_t                                    bindInfoCount,
-    const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos);
+    const VkBindAccelerationStructureMemoryInfoNV* pBindInfos);
 
-VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNVX(
+VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNV(
     VkCommandBuffer                             commandBuffer,
-    VkAccelerationStructureTypeNVX              type,
-    uint32_t                                    instanceCount,
+    const VkAccelerationStructureInfoNV*        pInfo,
     VkBuffer                                    instanceData,
     VkDeviceSize                                instanceOffset,
-    uint32_t                                    geometryCount,
-    const VkGeometryNVX*                        pGeometries,
-    VkBuildAccelerationStructureFlagsNVX        flags,
     VkBool32                                    update,
-    VkAccelerationStructureNVX                  dst,
-    VkAccelerationStructureNVX                  src,
+    VkAccelerationStructureNV                   dst,
+    VkAccelerationStructureNV                   src,
     VkBuffer                                    scratch,
     VkDeviceSize                                scratchOffset);
 
-VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNVX(
+VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNV(
     VkCommandBuffer                             commandBuffer,
-    VkAccelerationStructureNVX                  dst,
-    VkAccelerationStructureNVX                  src,
-    VkCopyAccelerationStructureModeNVX          mode);
+    VkAccelerationStructureNV                   dst,
+    VkAccelerationStructureNV                   src,
+    VkCopyAccelerationStructureModeNV           mode);
 
-VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNVX(
+VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNV(
     VkCommandBuffer                             commandBuffer,
     VkBuffer                                    raygenShaderBindingTableBuffer,
     VkDeviceSize                                raygenShaderBindingOffset,
@@ -8167,18 +8375,22 @@
     VkBuffer                                    hitShaderBindingTableBuffer,
     VkDeviceSize                                hitShaderBindingOffset,
     VkDeviceSize                                hitShaderBindingStride,
+    VkBuffer                                    callableShaderBindingTableBuffer,
+    VkDeviceSize                                callableShaderBindingOffset,
+    VkDeviceSize                                callableShaderBindingStride,
     uint32_t                                    width,
-    uint32_t                                    height);
+    uint32_t                                    height,
+    uint32_t                                    depth);
 
-VKAPI_ATTR VkResult VKAPI_CALL vkCreateRaytracingPipelinesNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesNV(
     VkDevice                                    device,
     VkPipelineCache                             pipelineCache,
     uint32_t                                    createInfoCount,
-    const VkRaytracingPipelineCreateInfoNVX*    pCreateInfos,
+    const VkRayTracingPipelineCreateInfoNV*     pCreateInfos,
     const VkAllocationCallbacks*                pAllocator,
     VkPipeline*                                 pPipelines);
 
-VKAPI_ATTR VkResult VKAPI_CALL vkGetRaytracingShaderHandlesNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesNV(
     VkDevice                                    device,
     VkPipeline                                  pipeline,
     uint32_t                                    firstGroup,
@@ -8186,20 +8398,21 @@
     size_t                                      dataSize,
     void*                                       pData);
 
-VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNV(
     VkDevice                                    device,
-    VkAccelerationStructureNVX                  accelerationStructure,
+    VkAccelerationStructureNV                   accelerationStructure,
     size_t                                      dataSize,
     void*                                       pData);
 
-VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructurePropertiesNVX(
+VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesNV(
     VkCommandBuffer                             commandBuffer,
-    VkAccelerationStructureNVX                  accelerationStructure,
+    uint32_t                                    accelerationStructureCount,
+    const VkAccelerationStructureNV*            pAccelerationStructures,
     VkQueryType                                 queryType,
     VkQueryPool                                 queryPool,
-    uint32_t                                    query);
+    uint32_t                                    firstQuery);
 
-VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNVX(
+VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNV(
     VkDevice                                    device,
     VkPipeline                                  pipeline,
     uint32_t                                    shader);
@@ -8296,6 +8509,46 @@
     uint32_t                                    marker);
 #endif
 
+#define VK_EXT_calibrated_timestamps 1
+#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 1
+#define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps"
+
+
+typedef enum VkTimeDomainEXT {
+    VK_TIME_DOMAIN_DEVICE_EXT = 0,
+    VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1,
+    VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2,
+    VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3,
+    VK_TIME_DOMAIN_BEGIN_RANGE_EXT = VK_TIME_DOMAIN_DEVICE_EXT,
+    VK_TIME_DOMAIN_END_RANGE_EXT = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT,
+    VK_TIME_DOMAIN_RANGE_SIZE_EXT = (VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT - VK_TIME_DOMAIN_DEVICE_EXT + 1),
+    VK_TIME_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkTimeDomainEXT;
+
+typedef struct VkCalibratedTimestampInfoEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkTimeDomainEXT    timeDomain;
+} VkCalibratedTimestampInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains);
+typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t*                                   pTimeDomainCount,
+    VkTimeDomainEXT*                            pTimeDomains);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetCalibratedTimestampsEXT(
+    VkDevice                                    device,
+    uint32_t                                    timestampCount,
+    const VkCalibratedTimestampInfoEXT*         pTimestampInfos,
+    uint64_t*                                   pTimestamps,
+    uint64_t*                                   pMaxDeviation);
+#endif
+
 #define VK_AMD_shader_core_properties 1
 #define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1
 #define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties"
@@ -8321,6 +8574,29 @@
 
 
 
+#define VK_AMD_memory_overallocation_behavior 1
+#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1
+#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior"
+
+
+typedef enum VkMemoryOverallocationBehaviorAMD {
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_BEGIN_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_END_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD,
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_RANGE_SIZE_AMD = (VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD + 1),
+    VK_MEMORY_OVERALLOCATION_BEHAVIOR_MAX_ENUM_AMD = 0x7FFFFFFF
+} VkMemoryOverallocationBehaviorAMD;
+
+typedef struct VkDeviceMemoryOverallocationCreateInfoAMD {
+    VkStructureType                      sType;
+    const void*                          pNext;
+    VkMemoryOverallocationBehaviorAMD    overallocationBehavior;
+} VkDeviceMemoryOverallocationCreateInfoAMD;
+
+
+
 #define VK_EXT_vertex_attribute_divisor 1
 #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3
 #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
@@ -8516,6 +8792,55 @@
     VkCheckpointDataNV*                         pCheckpointData);
 #endif
 
+#define VK_EXT_pci_bus_info 1
+#define VK_EXT_PCI_BUS_INFO_SPEC_VERSION  1
+#define VK_EXT_PCI_BUS_INFO_EXTENSION_NAME "VK_EXT_pci_bus_info"
+
+typedef struct VkPhysicalDevicePCIBusInfoPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint16_t           pciDomain;
+    uint8_t            pciBus;
+    uint8_t            pciDevice;
+    uint8_t            pciFunction;
+} VkPhysicalDevicePCIBusInfoPropertiesEXT;
+
+
+
+#define VK_EXT_scalar_block_layout 1
+#define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1
+#define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout"
+
+typedef struct VkPhysicalDeviceScalarBlockLayoutFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           scalarBlockLayout;
+} VkPhysicalDeviceScalarBlockLayoutFeaturesEXT;
+
+
+
+#define VK_GOOGLE_hlsl_functionality1 1
+#define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 0
+#define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1"
+
+
+#define VK_GOOGLE_decorate_string 1
+#define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 0
+#define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string"
+
+
+#define VK_EXT_separate_stencil_usage 1
+#define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1
+#define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage"
+
+typedef struct VkImageStencilUsageCreateInfoEXT {
+    VkStructureType      sType;
+    const void*          pNext;
+    VkImageUsageFlags    stencilUsage;
+} VkImageStencilUsageCreateInfoEXT;
+
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 7eaf7b2..fed8481 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -39,6 +39,9 @@
         "-Wno-switch-enum",
         "-Wno-undef",
 
+        // Have clang emit complete debug_info.
+        "-fstandalone-debug",
+
         //"-DLOG_NDEBUG=0",
     ],
 
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index 629ebb1..df86af0 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -556,6 +556,7 @@
         "vkGetDisplayModeProperties2KHR",
         "vkGetDisplayPlaneCapabilities2KHR",
         "vkGetInstanceProcAddr",
+        "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT",
         "vkGetPhysicalDeviceDisplayPlaneProperties2KHR",
         "vkGetPhysicalDeviceDisplayProperties2KHR",
         "vkGetPhysicalDeviceExternalBufferProperties",
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 1f4df1e..f04eb03 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -1149,6 +1149,7 @@
   {{else if eq $ext "VK_EXT_direct_mode_display"}}true
   {{else if eq $ext "VK_EXT_display_surface_counter"}}true
   {{else if eq $ext "VK_EXT_display_control"}}true
+  {{else if eq $ext "VK_FUCHSIA_imagepipe_surface"}}true
   {{else if eq $ext "VK_MVK_ios_surface"}}true
   {{else if eq $ext "VK_MVK_macos_surface"}}true
   {{else if eq $ext "VK_NN_vi_surface"}}true
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index efe622d..3da4336 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -325,6 +325,13 @@
   }
 };
 
+template <>
+struct EnumTraits<VkDriverIdKHR> {
+  static uint32_t min() { return VK_DRIVER_ID_BEGIN_RANGE_KHR; }
+  static uint32_t max() { return VK_DRIVER_ID_END_RANGE_KHR; }
+  static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+};
+
 // VkSparseImageFormatProperties
 
 template <typename Visitor>
@@ -544,6 +551,31 @@
 
 template <typename Visitor>
 inline bool Iterate(Visitor* visitor,
+                    VkJsonExtDriverProperties* properties) {
+  return visitor->Visit("driverPropertiesKHR",
+                        &properties->driver_properties_khr);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceDriverPropertiesKHR* properties) {
+  return visitor->Visit("driverID", &properties->driverID) &&
+         visitor->Visit("driverName", &properties->driverName) &&
+         visitor->Visit("driverInfo", &properties->driverInfo) &&
+         visitor->Visit("conformanceVersion", &properties->conformanceVersion);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkConformanceVersionKHR* version) {
+  return visitor->Visit("major", &version->major) &&
+         visitor->Visit("minor", &version->minor) &&
+         visitor->Visit("subminor", &version->subminor) &&
+         visitor->Visit("patch", &version->patch);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
                     VkJsonExtVariablePointerFeatures* features) {
   return visitor->Visit("variablePointerFeaturesKHR",
                         &features->variable_pointer_features_khr);
@@ -770,13 +802,19 @@
     case VK_API_VERSION_1_0:
       ret &= visitor->Visit("properties", &device->properties) &&
              visitor->Visit("features", &device->features) &&
-             visitor->Visit("VK_KHR_variable_pointers",
-                            &device->ext_variable_pointer_features) &&
              visitor->Visit("memory", &device->memory) &&
              visitor->Visit("queues", &device->queues) &&
              visitor->Visit("extensions", &device->extensions) &&
              visitor->Visit("layers", &device->layers) &&
              visitor->Visit("formats", &device->formats);
+      if (device->ext_driver_properties.reported) {
+        ret &= visitor->Visit("VK_KHR_driver_properties",
+                            &device->ext_driver_properties);
+      }
+      if (device->ext_variable_pointer_features.reported) {
+        ret &= visitor->Visit("VK_KHR_variable_pointers",
+                            &device->ext_variable_pointer_features);
+      }
   }
   return ret;
 }
diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h
index 4f97c3e..450fb24 100644
--- a/vulkan/vkjson/vkjson.h
+++ b/vulkan/vkjson/vkjson.h
@@ -52,11 +52,23 @@
   std::vector<VkExtensionProperties> extensions;
 };
 
+struct VkJsonExtDriverProperties {
+  VkJsonExtDriverProperties() {
+    reported = false;
+    memset(&driver_properties_khr, 0,
+           sizeof(VkPhysicalDeviceDriverPropertiesKHR));
+  }
+  bool reported;
+  VkPhysicalDeviceDriverPropertiesKHR driver_properties_khr;
+};
+
 struct VkJsonExtVariablePointerFeatures {
   VkJsonExtVariablePointerFeatures() {
+    reported = false;
     memset(&variable_pointer_features_khr, 0,
            sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR));
   }
+  bool reported;
   VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features_khr;
 };
 
@@ -87,6 +99,7 @@
   }
   VkPhysicalDeviceProperties properties;
   VkPhysicalDeviceFeatures features;
+  VkJsonExtDriverProperties ext_driver_properties;
   VkJsonExtVariablePointerFeatures ext_variable_pointer_features;
   VkPhysicalDeviceMemoryProperties memory;
   std::vector<VkQueueFamilyProperties> queues;
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index 4ec442a..05d4dfe 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -71,11 +71,16 @@
                              const char* const* instance_extensions) {
   VkJsonDevice device;
 
+  PFN_vkGetPhysicalDeviceProperties2KHR vkpGetPhysicalDeviceProperties2KHR =
+      nullptr;
   PFN_vkGetPhysicalDeviceFeatures2KHR vkpGetPhysicalDeviceFeatures2KHR =
       nullptr;
   if (instance != VK_NULL_HANDLE &&
       HasExtension("VK_KHR_get_physical_device_properties2",
                    instance_extension_count, instance_extensions)) {
+    vkpGetPhysicalDeviceProperties2KHR =
+        reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(
+            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR"));
     vkpGetPhysicalDeviceFeatures2KHR =
         reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
             vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
@@ -98,15 +103,32 @@
                                      device.layers.data());
   }
 
-  vkGetPhysicalDeviceProperties(physical_device, &device.properties);
   if (HasExtension("VK_KHR_get_physical_device_properties2",
                    instance_extension_count, instance_extensions)) {
+    VkPhysicalDeviceProperties2KHR properties = {
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
+        nullptr,
+        {} // properties
+    };
+    if (HasExtension("VK_KHR_driver_properties", device.extensions)) {
+      device.ext_driver_properties.reported = true;
+      device.ext_driver_properties.driver_properties_khr.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
+      device.ext_driver_properties.driver_properties_khr.pNext =
+          properties.pNext;
+      properties.pNext =
+          &device.ext_driver_properties.driver_properties_khr;
+    }
+    vkpGetPhysicalDeviceProperties2KHR(physical_device, &properties);
+    device.properties = properties.properties;
+
     VkPhysicalDeviceFeatures2KHR features = {
         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,
         nullptr,
         {}  // features
     };
     if (HasExtension("VK_KHR_variable_pointers", device.extensions)) {
+      device.ext_variable_pointer_features.reported = true;
       device.ext_variable_pointer_features.variable_pointer_features_khr.sType =
           VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
       device.ext_variable_pointer_features.variable_pointer_features_khr.pNext =
@@ -117,6 +139,7 @@
     vkpGetPhysicalDeviceFeatures2KHR(physical_device, &features);
     device.features = features.features;
   } else {
+    vkGetPhysicalDeviceProperties(physical_device, &device.properties);
     vkGetPhysicalDeviceFeatures(physical_device, &device.features);
   }
   vkGetPhysicalDeviceMemoryProperties(physical_device, &device.memory);